LL gcd(LL a, LL b){ return b == 0 ? a : gcd(b, a % b); }
lcm(a, b) = a / gcd(a, b) * b
扩展欧几里得算法(exGCD)
目标: 寻找一对整数$(x, y)$,使$ax+by=gcd(a,b)$
1 2 3 4
voidexgcd(LL a, LL b, LL& d, LL& x, LL& y){ if (!b) { d = a; x = 1; y = 0; } //d为gcd(a, b) else { exgcd(b, a % b, d, y, x); y -= x * (a / b); } }
裴蜀定理
$ax+by=c$且$x,y$全为正整数,则当且仅当$gcd(a, b)|c$
素数相关
Eratosthenes筛法
1 2 3 4 5 6 7 8 9 10 11
bool vis[maxn]; int prime[maxn]; voidgetprime(int n){ int m = (int)sqrt(n + 0.5), num = 0; memset(vis, 0, sizeof(vis)); vis[0] = vis[1] = 1; for (int i = 2; i <= m; ++i) if (!vis[i]) { prime[++num] = i; for (int j = i * i; j <= n; j += i) vis[j] = 1; } }
欧拉线性筛
1 2 3 4 5 6 7 8 9 10 11 12 13
voidgetprime(int n){ vis[1] = true; for (int i = 2; i <= n; i++) { if (!vis[i]) { prime[++cnt] = i; } for (int j = 1; j <= cnt; j++) { int v = i * prime[j]; if (v > n) break; vis[v] = true; } } }
LL Random(LL n){ return (LL)((double)rand() / RAND_MAX * n + 0.5); } boolWitness(LL a, LL n){ LL m = n - 1; int j = 0; while (!(m & 1)) { j++; m >>= 1; } LL x = pow_mod(a, m, n); if (x == 1 || x == n - 1) returnfalse; while (j--) { x = x * x % n; if (x == n - 1) returnfalse; } returntrue; } boolMiller_Rabin(LL n){ if (n < 2) returnfalse; if (n == 2) returntrue; if (!(n & 1)) returnfalse; for (int i = 1; i <= 30; ++i) { LL a = Random(n - 2) + 1; if (Witness(a, n)) returnfalse; } returntrue; }
模算术
$$ (a + b)\bmod n = ((a\bmod n) + (b\bmod n))\bmod n\\ (a - b)\bmod n = ((a\bmod n) - (b\bmod n) + n)\bmod n\\ ab\mod n = (a\bmod n)(b\bmod n)\bmod n $$
快速乘 $ab\bmod n$
1 2 3 4 5 6 7 8 9
LL mul_mod(LL a, LL b, LL n){ LL res = 0; while (b > 0) { if (b & 1) res = (res + a) % n; a = (a + a) % n; b >>= 1; } return res; }
快速幂 $a^p\bmod n$
1 2 3 4 5 6 7
LL pow_mod(LL a, LL p, LL n){ if (p == 0 && n == 1) return0; if (p == 0) return1; LL ans = pow_mod(a, p / 2, n); ans = ans * ans % n; if (p % 2 == 1) ans = ans * a % n; return ans; }
使用位运算:
1 2 3 4 5
LL pow_mod(LL a, LL p, LL n){ a %= n; LL ans = 1; for (; p; p >>= 1, a *= a, a %= n) if(p & 1) ans = ans * a % n; return ans; }
inteuler_phi(int n){ int m = (int)sqrt(n + 0.5); int ans = n; for (int i = 2; i <= m; ++i) if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } if (n > 1) ans = ans / n * (n - 1); return ans; }
筛欧拉函数表
1 2 3 4 5 6 7 8 9
int phi[maxn]; voidphi_table(int n){ for (int i = 2; i <= n; ++i) phi[i] = 0; phi[1] = 1; for (int i = 2; i <= n; ++i) if (!phi[i]) for (int j = i; j <= n; j += i) { if (!phi[j]) phi[j] = j; phi[j] = phi[j] / i * (i - 1); } }
同余式定理
欧拉定理
若$gcd(a, n) = 1$,则$a^{\varphi(n)}\equiv 1\pmod n$
费马小定理
若$p$为质数,则$a^{p-1}\equiv 1\pmod p$
威尔逊定理
若$p$为质数,则$(p-1)!\equiv -1\pmod p$
乘法逆元
$$a\div b\bmod n = a\times b^{-1}\bmod n$$ $b^{-1}$称为$b$在模$n$意义下的逆元
$n$为质数
使用费马小定理, $a^{-1} = a^{n - 2}$
$n$不为质数
递归求解
1 2 3 4 5
LL inv(LL a, LL n){ LL d, x, y; exgcd(a, n, d, x, y); return d == 1 ? (x + n) % n : -1; }
筛逆元表
1 2 3 4 5 6 7
int inv_table[maxn]; voidgetinv(int n, int p){ inv_table[1] = 1; for (int i = 2; i <= n; ++i) { inv_table[i] = (LL)(p - p / i) * inv_table[p % i] % p; } }
同余方程
$ax\equiv b\pmod n$可以化为$ax+ny=b$使用扩展欧拉定理解决
中国剩余定理(China Remainder Theorem)
求解$x\equiv a_i\pmod {m_i}$满足$m_i$两两互质
1 2 3 4 5 6 7 8 9 10
LL crt(int n, int* a, int* m){ LL M = 1, d, y, x = 0; for (int i = 0; i < n; ++i) M *= m[i]; for (int i = 0; i < n; ++i) { LL w = M / m[i]; exgcd(m[i], w, d, d, y); x = (x + y * w * a[i]) % M; } return (x + M) % M; }
扩展中国剩余定理(exCRT)
$m_i$不一定两两互质
1 2 3 4 5 6 7 8 9 10 11 12 13
LL excrt(LL n, LL* a, LL* m){ LL x, y, k, M = m[0], ans = a[0]; for (int i = 1; i < n; ++i) { LL A = M, B = m[i], C = (a[i] - ans % B + B) % B, gcd; exgcd(A, B, gcd, x, y); LL bg = B / gcd; if (C % gcd != 0) return-1; x = mul_mod(x, C / gcd, bg); ans += x * M; M *= bg; ans = (ans % M + M) % M; } return (ans % M + M) % M; }
离散对数(BSGS)
求解$a^x\equiv b\pmod n$满足$n$为质数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
intlog_mod(int a, int b, int n){ int m, v, e = 1, i; m = (int)sqrt(n + 0.5); v = inv(pow_mod(a, m, n), n); map<int, int> x; x[1] = 0; for (i = 1; i < m; ++i) { e = mul_mod(e, a, n); if (!x.count(e)) x[e] = i; } for (i = 0; i < m; ++i) { if (x.count(b)) return i * m + x[b]; b = mul_mod(b, v, n); } return-1; }