1. 程式人生 > >中國剩余定理(CRT) - 學習筆記

中國剩余定理(CRT) - 學習筆記

www. 問題: 表示 crt line inline pmod 需要 產生

中國剩余定理 學習筆記

問題

中國剩余定理用來解決如下問題:

求關於\(x\)的方程組

\[\begin{cases} x \equiv a_1 \pmod{p_1} \\ x \equiv a_2 \pmod{p_2} \\ ... \\ x \equiv a_n\pmod{p_n}\end{cases}\]

的最小非負整數解。

其中\(p_i\)兩兩互質。

前置技能

擴展歐幾裏得求乘法逆元

求解

\(M=\prod_{i=1}^{n} p_i,d_i=\frac{M}{p_i}\),即\(d_i\)表示除\(p_i\)外所有\(p\)的乘積。

\(inv_i\)表示\(d_i\)在模\(p_i\)

域下的逆元(因為\(p\)兩兩互質,所以\(d_i\)一定與\(p_i\)互質,所以一定存在逆元),即\(inv_i \times d_i \equiv 1 \pmod{p_i}\)。記\(x_i=inv_i\times d_i\),則:

  1. 因為\(d_i\)能被除\(p_i\)外的所有\(p\)整除,所以\(x_i\)一定能被除\(p_i\)外的所有\(p\)整除,所以\(x_ia_i\)一定能被除\(p_i\)外的所有\(p\)整除。
  2. \(x_i\equiv 1 \pmod{p_i}\),所以\(a_ix_i\equiv a_i \pmod{p_i}\)

根據以上兩條推論可得,答案為\(\left( \sum_{i=1}^{n} a_ix_i \right) \bmod M\)

。因為對於第\(i\)個方程,根據推論1,對於所有的\(j\ne i\)\(a_jx_j\)不會對該方程組產生貢獻,即\(a_jx_j\equiv 0 \pmod{p_i} (j\ne i)\)。只有\(a_ix_i\)會對第\(i\)個方程產生貢獻,且根據推論2,恰好會產生\(a_i\)的貢獻。又因為對於所有\(i\)\(M\equiv 0\pmod{p_i}\),所以答案加上或減去若幹個\(M\)都滿足方程組。求的是最小非負整數解,所以答案\(\bmod M\)

代碼

中國剩余定理模板題:[TJOI2009]猜數字

因為出題人過於毒瘤直接乘會爆long long,所以需要快(gui)速乘,即把快速冪的乘法改成加法。

#include <cstdio>
long long exgcd(long long a, long long b, long long &x, long long &y){
    if (!b) return x = 1, y = 0, a;
    long long x0, y0, g = exgcd(b, a % b, x0, y0);
    return x = y0, y = x0 - a / b * y0, g;
}
int n, a[15], p[15];
long long inv(long long a, long long p){
    long long x, y, g = exgcd(a, p, x, y);
    if (g != 1) return -1;
    return (x % p + p) % p;
}
long long qmul(long long a, long long b, long long p){
    long long s = 0;
    for (a %= p, b %= p; b; b >>= 1, a = (a + a) % p) b & 1 ? s = (s + a) % p : 0;
    return s; 
}
int main(){
    scanf("%d", &n);
    for (register int i = 1; i <= n; ++i) scanf("%d", a + i);
    for (register int i = 1; i <= n; ++i) scanf("%d", p + i);
    for (register int i = 1; i <= n; ++i) a[i] = (a[i] % p[i] + p[i]) % p[i];
    long long m = 1, ans = 0;
    for (register int i = 1; i <= n; ++i) m = m * p[i];
    for (register int i = 1; i <= n; ++i){
        long long d = m / p[i], d_ = inv(d, p[i]);
        (ans += qmul(qmul(d, d_, m), a[i], m)) %= m;
    }
    printf("%lld", ans);
}

中國剩余定理(CRT) - 學習筆記