AIGC标识 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. 质因数分解后直接计算。
  2. 线性筛法一次性求出 \(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\)。
算法步骤:

  1. 若 \(b=0\),则 \(x=1,y=0\)。
  2. 否则递归计算 \(g = exgcd(b, a\%b, y, x)\),则 \(y = y - (a/b)*x\)。
  3. 返回 \(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)

问题:求解同余方程组

\[\begin{cases} x \equiv a_1 \pmod{m_1} \\ x \equiv a_2 \pmod{m_2} \\ \vdots \\ x \equiv a_k \pmod{m_k} \end{cases} \]

其中 \(m_i\) 两两互质(经典形式)。
算法步骤(经典 CRT):

  1. 计算 \(M = \prod m_i\)。
  2. 对每个 \(i\),计算 \(M_i = M / m_i\)。
  3. 求 \(t_i\) 使 \(M_i \cdot t_i \equiv 1 \pmod{m_i}\)(即 \(M_i\) 模 \(m_i\) 的逆元)。
  4. 构造解 \(x = \sum a_i \cdot M_i \cdot t_i \pmod M\)。
  5. 最小非负解为 \(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;
}
posted @ 2026-09-20 15:59  Aries2011  阅读(27)  评论(0)    收藏  举报