• 洛谷 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());
    }
  • 相关阅读:
    pygame中的图像和音乐
    pygame中鼠标画直线
    Python-GUI:button及entry的应用
    Linux查看物理CPU个数、核数、逻辑CPU个数
    阿里云nas使用记录
    字符集错误解决
    firewalld防火墙命令规则设置
    Linux之TCPIP内核参数
    nginx 301跳转https后post请求失效问题解决
    TCP queue 的一些问题
  • 原文地址:https://www.cnblogs.com/passione-123456/p/11697338.html
Copyright © 2020-2023  润新知