洛谷 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 就是答案....

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

// 已知前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],M=bi[1];
    for(int i=2;i<=n;i++){
        int a=M,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 
        ans+=x*M; //答案 
        M*=bg;//更新LCM 
        ans=(ans%M+M)%M; //%M是因为 x=x0+t*M 写成同余方程即为 x ≡ x0(mod M)%M不影响答案正确性 
    }
    return (ans%M+M)%M;
}//扩展中国剩余定理 
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&bi[i],&ai[i]);
    }
    printf("%lld",excrt());
}

猜你喜欢

转载自www.cnblogs.com/passione-123456/p/11697338.html