这篇 Blog 记录了一些数论代数的板子,以便不时之需。 线性筛素数 cpp复制代码#include <bits/stdc++.h> using namespace std; const int MAXN = 1e7 + 3; bool isprime[MAXN]; void sieve(int n){ memset(isprime, true, sizeof(isprime)); isprime[0] = isprime[1] = false; for (int i = 2; i <= n; i++) { if (isprime[i]) for (int j = i*2; j <= n; j += i) isprime[j] = false; } } int main(){ int n, m, x; cin >> n >> m; sieve(n); while (m--) { cin >> x; if (isprime[x]) cout << "Yes" << endl; else cout << "No" << endl; } return 0; } 扩展欧几里得算法 求解不定方程 ax+by=gcd(a,b),a≥bax+by=\gcd(a,b),a\geq bax+by=gcd(a,b),a≥b cpp复制代码void exgcd(int a, int b, int &x, int &y) { if (!b) x = 1, y = 0; else { exgcd(b, a % b, y, x); y = y - x * (a / b); } } 乘法逆元 设正整数模 mmm,∀a\forall a∀a 满足 (a,m)=1(a,m)=1(a,m)=1,∃b\exists b∃b 满足 ab≡1( mod m)ab\equiv 1(\bmod\ m)ab≡1(mod m),称 bbb 为模 mmm 意义下 aaa 的逆元。 求逆元只需解线性同余方程 ab+mt=1ab+mt=1ab+mt=1 即可。 cpp复制代码#include <bits/stdc++.h> using namespace std; int n, p; void exgcd(int a, int b, int &x, int &y) { if (!b) x = 1, y = 0; else { exgcd(b, a % b, y, x); y -= a / b * x; } } int main() { scanf("%d%d", &n, &p); for (int i = 1; i <= n; i++) { int x = 0, y = 0; exgcd(i, p, x, y); x = (x + p) % p; printf("%d\n", x); } return 0; } 线性筛欧拉 φ(n)\varphi(n)φ(n)表示 1 到 n 中与 n 互质的整数的个数。 φ(pk)=pk−pk−1=(p−1)pk−1\varphi(p^k)=p^k-p^{k-1}=(p-1)p^{k-1}φ(pk)=pk−pk−1=(p−1)pk−1 cpp复制代码notprime[1] = true; for (int i = 2; i <= n; i++) { if (!notprime[i]) { prime[++psz] = i; phi[i] = i - 1; } for (int j = 1; j <= psz; j++) { int k = i * prime[j]; if (k > n) break; notprime[i * prime[j]] = true; if (i % prime[j] == 0) { phi[k] = phi[i] * prime[j]; break; } else { phi[k] = phi[i] * (prime[j] - 1); } } }