洛谷 p4777 扩展中国剩余定理(excrt)

前置知识:扩展欧几里得、裴蜀定理、求解线性同余方程;

题意:解同余方程组 模数不互质...

   解线性同余方程用exgcd        比如解 ax≡c(mod b)

                               也就是 ax+by=c,

                               exgcd可以解出 ax+by=gcd(a,b) ,

                               方程同乘一个c/gcd(a,b)也就是 a*(x*c/gcd)+b(y*c/gcd)=c

                               所以exgcd解出x再乘一个c/gcd(a,b)就是一组可行解

   解同余方程组  已知前i-1项通解 x0+k*LCM k∈Z ,

                引入第i项时 求出一个最小的t满足 x0+t*LCM ≡ ai(mod mi) 此时x=x0+t*LCM 就是答案....

                怎么解这个方程?移下向 t*LCM ≡ ai-x0(mod mi),满足ax≡c(mod b) exgcd解就行了

                有些题还要用裴蜀定理判无解 这道不用 看代码...

// 已知前i-1项通解 x0+k*LCM k∈Z 
//引入第i项时 求出一个最小的t满足 x0+t*LCM ≡ ai(mod mi) 此时x=x0+t*LCM 
//                         移向   t*LCM   ≡ ai-x0 (mod mi)
//                         扩欧 求 即可        
//            ax≡c(mod b)  exgcd算出  ax≡1(mod b) x再乘上c/gcd(a,b)即可 c%gcd(a,b)!=0时无解 
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long lt;
int x,y;
int n,ai[100000],bi[100000];
int mul(int a,int b, int p){
    int res=0;
    while(b){
        if(b&1){
            res=(res+a)%p;
        }
        a=(a+a)%p;
        b>>=1;
    }
    return res;
}//龟速乘 
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-(a/b)*y;
    return d;
}//扩欧 
int excrt(){
    int ans=ai[1],LCM=bi[1];
    for(int i=2;i<=n;i++){
        int a=LCM,b=bi[i],c=(ai[i]-ans%b+b)%b;//a ≡c(mod b) 
        int gcd=exgcd(a,b,x,y),bg=b/gcd;//算t*LCM   ≡ gcd(mod mi) 
        if(c%gcd!=0)return -1;//无解情况 
        x=mul(x,c/gcd,bg);//t*LCM   ≡ ai-x0 (mod mi)  先算 t*LCM   ≡ gcd (mod mi) 答案再乘上 (ai-x0)/gcd即为t 
                    // 为什么要模b/gcd呢 我们知道 x=x0+t*LCM 写成同余方程即为 x ≡ x0(mod LCM)所以%LCM对答案没影响 
                    //但是 直接%当前的LCM可能会炸 所以我们一层一层模  我们知道LCM1=LCM0*(b1/gcd),
                    //LCM0再上一层已经模过了(即x中已经过滤掉LCM0的倍数了) 我们只需要再模完(b1/gcd)就可以了 就相当于模LCM1了
        ans+=x*LCM; //答案 
        LCM*=bg;//更新LCM  
        ans=(ans%LCM+LCM)%LCM; 
    }
    return (ans%LCM+LCM)%LCM;
}//扩展中国剩余定理 
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&bi[i],&ai[i]);
    }
    printf("%lld",excrt());
}

 

posted @ 2019-10-18 11:23  passione  阅读(145)  评论(0编辑  收藏  举报