C++初等数论
初等数论
2.1 同余式
定义
若整数 \(a,b\) 除以正整数 \(m\) 的余数相同,则称 \(a\) 与 \(b\) 模 \(m\) 同余,记作 \(a \equiv b \pmod m\)。
性质
- 自反性、对称性、传递性。
- 同余可进行加法、减法、乘法运算。
- 若 \(a \equiv b \pmod m\),则 \(a^k \equiv b^k \pmod m\)。
- 若 \(ac \equiv bc \pmod m\) 且 \(\gcd(c,m)=1\),则 \(a \equiv b \pmod m\)。
线性同余方程
形如 \(ax \equiv b \pmod m\),求解 \(x\)。
- 令 \(g = \gcd(a,m)\),若 \(b \nmid g\) 则无解。
- 否则,方程等价于 \(\frac{a}{g}x \equiv \frac{b}{g} \pmod{\frac{m}{g}}\),此时 \(\gcd(\frac{a}{g}, \frac{m}{g})=1\)。
- 利用扩展欧几里得求逆元,得到 \(x_0 \equiv \frac{b}{g} \cdot (\frac{a}{g})^{-1} \pmod{\frac{m}{g}}\)。
- 所有解为 \(x = x_0 + k \cdot \frac{m}{g}\)(\(k \in \mathbb{Z}\))。
代码实现(求解最小非负整数解)
int linear_congruence(int a,int b,int m){
int x,y;
int g=exgcd(a,m,x,y); // exgcd 见 2.7
if(b%g!=0) return -1; // 无解
int mod=m/g;
int res = (x*(b/g)%mod + mod)%mod;
return res;
}
2.2 欧拉定理和欧拉函数
欧拉函数 \(\varphi(n)\) 表示 \(1\) 到 \(n\) 中与 \(n\) 互质的整数个数。
计算公式:\(\varphi(n) = n \prod_{p|n}(1-\frac{1}{p})\),其中 \(p\) 为 \(n\) 的不同质因子。
欧拉定理:若 \(\gcd(a,n)=1\),则 \(a^{\varphi(n)} \equiv 1 \pmod n\)。
应用:求逆元(当模数为合数且互质时),指数取模(降幂)。
欧拉函数求法:
- 质因数分解后直接计算。
- 线性筛法一次性求出 \(1..N\) 的欧拉函数。
代码实现(线性筛欧拉函数,同时筛质数)
vector<int> phi; // phi[i] 存储 φ(i)
vector<int> primes;
vector<bool> isComp;
void euler_sieve(int n){
phi.resize(n+1);
isComp.assign(n+1,false);
phi[1]=1;
for(int i=2;i<=n;i++){
if(!isComp[i]) { primes.push_back(i); phi[i]=i-1; }
for(int p: primes){
if(i*p>n) break;
isComp[i*p]=true;
if(i%p==0){
phi[i*p] = phi[i]*p;
break;
}else{
phi[i*p] = phi[i]*(p-1);
}
}
}
}
// 单个欧拉函数(质因数分解)
int phi_single(int n){
int res=n;
for(int i=2;i*i<=n;i++){
if(n%i==0){
while(n%i==0) n/=i;
res = res/i*(i-1);
}
}
if(n>1) res = res/n*(n-1);
return res;
}
欧拉定理降幂:若 \(a\) 与 \(m\) 互质,则 \(a^b \bmod m = a^{b \bmod \varphi(m)} \bmod m\)(适用于指数极大时)。
2.3 费马小定理
定理:若 \(p\) 为质数,且 \(\gcd(a,p)=1\),则 \(a^{p-1} \equiv 1 \pmod p\)。
应用:
- 快速求逆元:\(a^{-1} \equiv a^{p-2} \pmod p\)(模质数时)。
- 判定质数(不一定准确,如伪素数)。
代码实现(求逆元)
int mod_inv_fermat(int a,int p){
return modpow(a, p-2, p); // modpow 见快速幂
}
2.4 威尔逊定理
定理:若 \(p\) 为质数,则 \((p-1)! \equiv -1 \pmod p\)。
逆定理:若 \(n>1\) 且 \((n-1)! \equiv -1 \pmod n\),则 \(n\) 为质数(但实际检测不高效)。
应用:判断大质数(不常用),某些组合数问题的简化。
代码实现(验证定理,通常不直接用于编程)
bool wilson_test(int n){
if(n<2) return false;
int fact=1;
for(int i=2;i<=n-1;i++) fact=fact*i%n;
return fact==n-1;
}
2.5 裴蜀定理(Bézout's identity)
定理:对于整数 \(a,b\),存在整数 \(x,y\) 使得 \(ax+by = \gcd(a,b)\)。
更一般地,方程 \(ax+by = c\) 有整数解当且仅当 \(\gcd(a,b) \mid c\)。
应用:扩展欧几里得算法直接给出解;判断线性丢番图方程是否有解。
代码实现(解 \(ax+by=c\) 的一组整数解)
bool bezout_solve(int a,int b,int c,int &x,int &y){
int g=exgcd(a,b,x,y);
if(c%g!=0) return false;
x *= c/g;
y *= c/g;
return true;
}
2.6 逆元
定义:若 \(a \cdot x \equiv 1 \pmod m\),则称 \(x\) 为 \(a\) 模 \(m\) 的逆元,记作 \(a^{-1}\)。存在当且仅当 \(\gcd(a,m)=1\)。
求法:
- 费马小定理(模质数):\(a^{-1} = a^{p-2} \bmod p\)。
- 扩展欧几里得(模任意互质):解 \(ax+my=1\),\(x\) 即为逆元。
- 线性递推(模质数 \(p\)):\(inv[i] = p - (p/i) \cdot inv[p\%i] \bmod p\),可求 \(1..n\) 的逆元。
代码实现(三种方法)
// 1. 扩展欧几里得
int mod_inv_exgcd(int a,int m){
int x,y;
int g=exgcd(a,m,x,y);
if(g!=1) return -1; // 不存在
return (x%m+m)%m;
}
// 2. 费马(模质数)
int mod_inv_fermat(int a,int p){
return modpow(a,p-2,p);
}
// 3. 线性递推求 1..n 逆元(模质数 p)
vector<int> linear_inv(int n,int p){
vector<int> inv(n+1);
inv[1]=1;
for(int i=2;i<=n;i++){
inv[i] = p - (p/i) * inv[p%i] % p;
}
return inv;
}
2.7 扩展欧几里得算法(Exgcd)
原理:递归计算 \(\gcd(a,b)\) 并得到一组整数解 \(x,y\) 使 \(ax+by=g\)。
算法步骤:
- 若 \(b=0\),则 \(x=1,y=0\)。
- 否则递归计算 \(g = exgcd(b, a\%b, y, x)\),则 \(y = y - (a/b)*x\)。
- 返回 \(g\)。
时间复杂度:\(O(\log \min(a,b))\)。
代码实现
int exgcd(int a,int b,int &x,int &y){
if(b==0){ x=1; y=0; return a; }
int g=exgcd(b, a%b, y, x);
y -= a/b * x;
return g;
}
应用:求逆元、解线性同余方程、求不定方程整数解、求乘法逆元等。
2.8 孙子定理(中国剩余定理,CRT)
问题:求解同余方程组
其中 \(m_i\) 两两互质(经典形式)。
算法步骤(经典 CRT):
- 计算 \(M = \prod m_i\)。
- 对每个 \(i\),计算 \(M_i = M / m_i\)。
- 求 \(t_i\) 使 \(M_i \cdot t_i \equiv 1 \pmod{m_i}\)(即 \(M_i\) 模 \(m_i\) 的逆元)。
- 构造解 \(x = \sum a_i \cdot M_i \cdot t_i \pmod M\)。
- 最小非负解为 \(x \bmod M\)。
若不互质:采用扩展 CRT(合并两个方程)。
- 合并 \(x \equiv a_1 \pmod{m_1}\) 和 \(x \equiv a_2 \pmod{m_2}\):
- 令 \(g=\gcd(m_1,m_2)\),若 \((a_2-a_1)\%g\neq0\) 则无解。
- 利用扩展欧几里得求 \(k_1\) 使 \(m_1 k_1 + m_2 k_2 = a_2-a_1\),得到 \(x = a_1 + m_1 k_1\)。
- 合并后的模为 \(\text{lcm}(m_1,m_2)\),余数为 \(x \bmod \text{lcm}\)。
代码实现(经典 CRT,模数互质)
int crt(vector<int>& a, vector<int>& m){
int M=1;
for(int mod:m) M*=mod;
int ans=0;
for(int i=0;i<a.size();i++){
int Mi=M/m[i];
int inv=mod_inv_exgcd(Mi%m[i], m[i]); // 或使用扩展欧几里得
ans = (ans + a[i]*Mi%M * inv)%M;
}
return ans;
}
扩展 CRT(合并方式)
pair<int,int> ex_crt_merge(int a1,int m1,int a2,int m2){
// 合并 x ≡ a1 (mod m1), x ≡ a2 (mod m2)
int g=__gcd(m1,m2);
if((a2-a1)%g!=0) return {-1,-1}; // 无解
int k1,k2;
exgcd(m1/g, m2/g, k1, k2);
int l = m1/g*m2;
int ans = (a1 + m1 * (( (a2-a1)/g * k1 ) % (m2/g) )) % l;
if(ans<0) ans += l;
return {ans,l};
}
// 依次合并所有方程
int ex_crt(vector<int>& a, vector<int>& m){
int cur_a=a[0], cur_m=m[0];
for(int i=1;i<a.size();i++){
auto [new_a, new_m] = ex_crt_merge(cur_a,cur_m,a[i],m[i]);
if(new_a==-1) return -1;
cur_a=new_a; cur_m=new_m;
}
return cur_a % cur_m;
}
本文来自博客园,作者:Aries2011,转载请注明原文链接:https://www.cnblogs.com/Aries2011/p/23050115

浙公网安备 33010602011771号