中国剩余定理

中国剩余定理(CRT)

问题模型

求解同余方程组,其中模数 \(m_1,m_2,\dots,m_k\) 两两互质:

\[\begin{cases} x \equiv a_1(mod\; m_1)\\ x \equiv a_2(mod\; m_2)\\ \dots \\ x \equiv x_k(mod\; m_k) \end{cases} \]

构造思想

同余方程可以有任意多个,不影响求解。构造一个整数 \(x\),由 \(k\) 部分求和得到,每一部分只负责满足一个方程,而不影响其他方程。

令 $M=m_1\ast m_2\ast \cdots\ast m_k $

\[x = \sum_{i=1}^k a_i\cdot T_i \]

对于第 \(i\) 个方程,需要构造一个 \(T_i\),满足:

  • \(T_i \equiv 1(mod\; m_i)\)
  • \(T_i \equiv 0(mod\; m_j),j\neq i\)

构造步骤:

  1. \(M_i=M/m_i\),此时可得 \(M_i\equiv 0(mod\; m_j),j\neq i\)

  2. \(t_i = M_i^{-1}(mod\; m_i)\)

  3. \(T_i=M_it_i\)

通解公式

\[x=\sum_{i=1}^k a_k\cdot T_i(mod\; M) \]

【模板】中国剩余定理(CRT)/ 曹冲养猪

#include <iostream>
using namespace std;
using LL = long long;
const int N = 17;
LL a[N], b[N];
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL gcd = exgcd(b, a%b, y, x);
    y -= a / b * x;
    return gcd;
}
int main() {
    int n;
    scanf("%d", &n);
    LL x, y, tot = 1;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld%lld", a + i, b + i);
        tot *= a[i];
    }
    LL ans = 0;
    for (int i = 1; i <= n; ++i) {
        LL Mi = tot / a[i];
        exgcd(Mi, a[i], x, y);
        x = (x%a[i] + a[i]) % a[i];
        (ans += (__int128)Mi * b[i] % tot * x % tot) %= tot;
    }
    printf("%lld\n", ans);
}

扩展中国剩余定理(EXCRT)

\(m_1,m_2,\dots,m_k\) 不满足两两互质的条件时,需要使用此方法。

对同余方程逐个合并

考虑前两个方程:

\[\begin{cases} x \equiv a_1(mod\; m_1)\\ x \equiv a_2(mod\; m_2) \end{cases} \]

等价于 \(x=k_1m_1+a_1=k_2m_2+a_2\)

整理可得 \(m_1k_1-m_2k_2=a_1-a_2\)

将其看成关于 \(k_1,k_2\) 的不定方程 \(Ax+By=C\),其中 \(A=m_1,B=m_2,C=a_2-a_1\)

  1. 先使用 exgcd 判断是否有解:令 \(d=gcd(m_1,m_2), L = lcm(m_1,m_2),\)\(C\not\equiv 0(mod\; d)\),则该方程组无解;否则继续第 2 步

  2. 求特解:通过第一步算出的系数 \(k_1',k_2'\) 可得 \(k_1'm_1+k_2'm_2=d\),两边同时乘以 \(C/d\),可得 \(m_1\cdot(C/d\cdot k_1')+m_2(C/d\cdot k_2)=C\),即 \(k_1 = C/d\cdot k_1'\) 是一个特解

  3. 对方程左边进行调整(\(\pm L\cdot t\))可以得到无穷多组解(\(t\in Z\)):

\[m_1\cdot(C/d\cdot k_1' + L/m_1\cdot t) + m_2\cdot(C/d\cdot k_2' -L/m_2\cdot t) = C \]

前两个方程的通解形式:\(K=C/d\cdot k_1'+L/m_1\cdot t\)

  1. 回代:将 \(K\) 代回 \(x=k_1m_1+a_1\),得

\[\begin{aligned} x &= (C/d\cdot k_1' + L/m_1\cdot t)m_1 + a_1\\ &= C/d\cdot k_1'\cdot m_1 + a_1 + L \cdot t \end{aligned} \]

即得 \(x\equiv (C/d\cdot k_1'\cdot m_1 + a_1)(mod\; L)\)

\(a_1=C/d\cdot k_1'\cdot m_1 + a_1,b_1=L\),继续迭代后面的同余方程即可。

【模板】扩展中国剩余定理(EXCRT)

#include <iostream>
using namespace std;
using LL = long long;
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    LL gcd = exgcd(b, a%b, y, x);
    y -= a / b * x;
    return gcd;
}
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    LL n, a, b, aa, bb, c, gcd, x, y, lcm;
    cin >> n >> a >> b;
    while (--n) {
        cin >> aa >> bb;
        gcd = exgcd(a, aa, x, y);
        c = bb - b;
        if (c % gcd) {
            cout << "-1\n";
            return 0;
        }
        lcm = a / gcd * aa;
        b = ((__int128)c/gcd*x*a + b) % lcm;
        a = lcm;
    }
    cout << (b + a) % a << "\n";
}
posted @ 2026-01-26 14:27  飞花阁  阅读(1)  评论(0)    收藏  举报
//雪花飘落效果