扩展中国剩余定理模板

传送门

博客传送门

模板代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000005;
const int inf = 0x3f3f3f3f;
ll ai[maxn], bi[maxn];
int n;
ll mul(ll a, ll b, ll mod) {//快速乘
    ll res = 0;
    while (b>0) {
        if (b & 1) {
            res = (res + a) % mod;
        }
        a = (a + a) % mod;
        b >>= 1;
    }
    return res;
}
ll exgcd(ll a, ll b, ll& x, ll& y) {//扩展欧几里得
    ll ans;
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    ans = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return ans;
}
ll exec() {
    ll x, y, t, m, ans;
    m = bi[1], ans = ai[1];
    for (int i = 2; i <= n; i++) {
        ll a = m, b = bi[i], c = (ai[i] - ans % bi[i]+bi[i]) % bi[i];
        ll gcd = exgcd(a, b, x, y), bg = b / gcd;
        if (c % gcd != 0)return -1;//无解情况
        x = mul(x, c / gcd, bg);
        ans += x * m;//
        m *= bg;//lcm
        ans = (ans % m + m) % m;
    }
    return (ans % m + m) % m;
}
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld%lld", bi + i, ai + i);
    }
    printf("%lld\n", exec());
    return 0;
}

 

问题

求解同余方程组

\left\{\begin{aligned}x\equiv\ a_1(\mod m_1) \quad\\ x\equiv\ a_2(\mod m_2) \quad\\ x\equiv\ a_3(\mod m_3) \quad\\ ...\quad\\x\equiv\ a_k(\mod m_k) \quad\end{aligned}\right.x a1(modm1)x a2(modm2)x a3(modm3)...x ak(modmk)

其中 m_1,m_2,m_3...m_km1,m2,m3...mk不一定两两互质的整数, 求x的最小非负整数解

求解

假设已经求出前k-1个方程组成的同余方程组的一个解为x

且有 M=\prod_{i-1}^{k-1}m_iM=i1k1mi

(补充:代码实现中用的就是 M=LCM_{i-1}^{k-1}m_iM=LCMi1k1mi显然易证这样是对的,还更能防止溢出,上述是为了先方便理解,评论区就别问那么多次了=_=)

则前k-1个方程的方程组通解为 x+i*M(i\in Z)x+iM(iZ)

那么对于加入第k个方程后的方程组

我们就是要求一个正整数t,使得 x+t*M \equiv a_k(\mod m_k)x+tMak(modmk)

转化一下上述式子得 t*M \equiv a_k-x(\mod m_k)tMakx(modmk)

对于这个式子我们已经可以通过扩展欧几里得求解t

若该同余式无解,则整个方程组无解, 若有,则前k个同余式组成的方程组的一个解解为 x_k=x+t*Mxk=x+tM

所以整个算法的思路就是求解k次扩展欧几里得

posted @ 2021-04-27 10:41  cono奇犽哒  阅读(48)  评论(0)    收藏  举报