EXCRT学习笔记

扩展中国剩余定理(EXCRT)

\[\begin{cases} x \equiv b_1 \pmod{a_1} \\ x \equiv b_2 \pmod{a_2} \\ \vdots \\ x \equiv b_n \pmod{a_n} \end{cases} \]

观察这个式子,当模数不互质的时候中国剩余定理(CRT)已经不再适用,这时就请出比CRT功能更强的EXCRT,在竞赛中尤为常用。

下面朴素介绍:

做法其实就是把式子合二为一,做 \(n-1\) 次
比如合并

\[\begin{cases} x \equiv b_1 \pmod{a_1} \\ x \equiv b_2 \pmod{a_2} \\ \end{cases} \]

显然的,存在 \(p, q \in Z\), 使得

\[ x + a1*p = b1 \\ x + a2*q = b2\\ \]

消去$ x $ :

\[ a1 * p - a2 *q = b1 - b2 \]

这是形如 \(ax+by = c\) 的不定方程, 自然的,我们用裴祖定理判断有无解,用EXGCD求出\(a1 * p - a2 * q = gcd(a1, a2)\) 的一组特解,再乘上 \(\frac{b1 - b2}{gcd(a1, a2)}\) 可以得到特解 \(p_0, q_0\) , 于是就可以得到原方程的通解 :

\[ p = p_0 + \frac{a2}{gcd(a1, a2)} * k \\ q = q_0 + \frac{a1}{gcd(a1, a2)} * k \]

又因为前面已知 $x = b1 - a1 * p $, 带入p可以得到 :

\[x = b1 - a1 * (p_0 + \frac{a2}{gcd(a1, a2)} * k) \\ = b1 - a1 * p0 - \frac{a1 \ a2}{gcd(a1, a2)} * k \\ = b1 - a1 * p0 - Lcm(a1, a2) * k \]

最终我们得到了一个新的同余方程 :

\[ x \equiv b1 - a1 * p0 \pmod{Lcm(a1, a2)} \]

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

#include<bits/stdc++.h>
using namespace std;
// #define int long long
#define int __int128
#define rep(i, l, r) for(int i = (l); i <= (r); ++ i)
#define per(i, r, l) for(int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define endl '\n'
#define pii pair<int, int>
#define pb push_back

int exgcd(int a,int b, int &x, int &y) {
    if(b == 0) {
        x = 1;
        y = 0;
        return a;
    } else {
        int t = exgcd(b, a % b, y, x);
        y = y - a / b * x;
        return t;
    }
}
void Jail() {
    long long n;
    cin >> n;
    int A = 1, B = 0;
    rep(i, 1, n) {
        long long a, b;
        cin >> a >> b;
        int p, q;
        int g = exgcd(A, a, p, q);
        // if(abs(B - b) % g != 0) {
        //     cout << -1 << endl;
        //     return ;
        // }  
        p = (B - b) / g * p;
        B = B - A * p;
        A = a / g * A;
        B = (B % A + A) % A;
    }
    long long ans = (B % A + A) % A;
    cout << ans << endl;
}

signed main() {
	// freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) Jail();
    return 0;
}

例题

CF2223C

题解后面补

posted @ 2026-05-08 09:42  Koswel  阅读(18)  评论(0)    收藏  举报