自用的一些小技巧

时间复杂度

常见的算法对应的时间复杂度可以参考yxc的这个acw博客: https://www.acwing.com/blog/content/32/

无穷

一般把无穷大设置为0x3f3f3f3f,无穷小设置为0xc0c0c0c0,由于这两个数的每个字节都一样,所以可以用memset(array, 0x3f, sizeof array)来将数组设置为无穷大,无穷小同理

lowbit

  • 举例说明作用:lowbit(100100B) = 100B
  • 具体操作:lowbit(x) = x & (-x)

二维转一维

将二维的点(x, y)转化为唯一对应的编号:num = x * n + y(n是指这个二维图是n * n的;使用这个公式的前提是x,y都从0开始),用这个公式计算出的对应num的最大值为(n - 1) * n + n - 1 = n * n - 1,操作的时候直接写i < n * n会更优美一些

辗转相除

int gcd(int a, int b) {
  return b ? gcd(b, a % b) : a;
}

线性求逆元

inv[1] = 1;
for (int i = 2; i <= n; ++i) {
  inv[i] = (long long)(p - p / i) * inv[p % i] % p;
}

便捷调试

#define pvar(x) std::cout << #x << ": " << x << std::endl;

埃氏筛

void sieve(int n) {
	minp.assign(n + 1,0);
	primes.clear();
	for (int i= 2; i <= n; i ++) {
		if (minp[i] == 0) {
			minp[i] = i;
			primes.push_back(i);
		}
		for (auto p : primes) {
			if(i * p > n) {
				break;
			}
			minp[i * p] = p;
			if (p == minp[i]) {
				break;
			}
		}
	}
}
  • 两个容器中存储的分别是minp[i]:i的因数中最小的质数prime[i]:从1到n中的第i(从0开始)个质数
  • 基本流程:i从2开始遍历,首先进行判断,如果i没被筛掉过,说明i是质数,其minp是i本身,并将其push到primes的back;之后用该数与primes中的质数相乘,以筛掉后面的合数。
  • 为什么埃氏筛不可能漏掉合数:对于任意一个合数x,其一定能被拆分成p * a(其中p是一个质数,a是一个严格小于x的数,可能是质数也可能是合数),显然埃氏筛是能够保证这两个数的乘积在循环遍历到x前被标记的。
  • auto p : primes遍历中最后的if剪枝的正确性:假设i的最小质因数为pmin,其某个非最小质因数为p1,p1 * i == x == p1 * pmin * a,a为一个大于i且小于x的数,这意味着i和自己非最小质因数p1的乘积是一定会被后面的某次循环给覆盖掉的,故而没有必要遍历后面的质数。

未完待续。。。

posted on 2023-08-08 15:42  wuhu12345  阅读(19)  评论(0)    收藏  举报

导航