自用的一些小技巧
时间复杂度
常见的算法对应的时间复杂度可以参考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的乘积是一定会被后面的某次循环给覆盖掉的,故而没有必要遍历后面的质数。
未完待续。。。
浙公网安备 33010602011771号