扩展中国剩余定理

在这里插入图片描述
现在,m1,m2,…mn之间没有任何关系。

只考虑两个怎么处理?

可以得到:x=a1+k1∗m1;x=a2+k2∗m2

所以 a1+k1∗m1=a2+k2∗m2

k2∗m2−k1∗m1=a1−a2;

很像:a×x+b×y=c

设m1,m2 的gcd 为 g

设a1−a2=c

当c不是g的倍数的时候,那就完了。(exgcd无解情况)

如果是,就用exgcd求出k2×m2+k1×m1=gcd(m1,m2)的k1

因为c是g的倍数,所以,两边同时乘上c/g,即k1乘上c/g

就得到了k2×m2+k1×m1=c的解k1。

当然,最好k1 再模一下m2 (k1,k2做出调整),防止爆longlong

然后可以反推x,

但是注意,我们列的原方程是:k2×m2−k1×m1=c

差一个符号,所以k1 实际上是 −k1

x=−k1×m1+a1;

这样就求出了x。(可以把这个x0转化成最小的非负数解)

这个x符合第一个方程,也符合第二个方程。设这个x为x0

所以,可以得到通解是:x=x0+k×lcm(m1,m2)

满足这个条件的x就满足第一第二两个方程。满足第一第二两个方程的所有的解也都是这个方程的解。

所以第一第二个方程和这个方程是等价的。

将这个方程转化一下,可以得到新的同余方程:x=x0(modlcm(m1,m2))

这样,我们成功的把两个方程转化成了一个方程,以此类推。

最后留下的这个方程,它的x_0的最小非负数解,就是我们要的最终答案!!!!!!!!!!!!!!


ll ai[maxn], bi[maxn], 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){
    if(b == 0){x = 1; y = 0; return a;}
    ll gcd = exgcd(b, a % b, x, y);
    ll tp = x;
    x = y; y = tp - a / b * y;
    return gcd;
}
ll excrt(){
    ll x, y, k;
    ll M = bi[1], ans = ai[1];//第一个方程的解特判
    for(int i = 2; i <= n; i++){
        ll a = M, b = bi[i], c = (ai[i] - ans % b + b) % b;//ax≡c(mod b)
        ll gcd = exgcd(a, b, x, y), bg = b / gcd;
        if(c % gcd != 0) return -1; //判断是否无解,然而这题其实不用
        x = mul(x, c / gcd, bg);//把x转化为最小非负整数解
        ans += x * M;//更新前k个方程组的答案
        M *= bg;
        ans = (ans % M + M) % M;
    }
    return (ans % M + M) % M;
}
 
int main(){
    scanf("%lld", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%lld%lld", &bi[i], &ai[i]);
    printf("%lld",excrt());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值