• 【模板】扩展中国剩余定理(EXCRT)


    洛咕

    题意:(left{egin{aligned}xequiv a_1(mod b_1) quad\ xequiv a_2(mod b_2) quad\ xequiv a_3(mod b_3) quad\ ...quad\xequiv a_n(mod b_n) quadend{aligned} ight.)

    其中(b_1,b_2,b_3...b_n)不一定两两互质,求x的最小非负整数解.

    分析:中国剩余定理中(b_1,b_2,b_3...b_n)保证了两两互质,而扩展中国剩余定理中没有,所以它们两个没有半毛钱关系.扩展中国剩余定理只需要用到扩展欧几里得(广告).

    假设已经求出前k-1个方程组成的同余方程组的一个解为ans,且有(M=prod_{i=1}^{k-1}b_i)(这里理解为最小公倍数),则前k-1个方程构成的方程组的通解为(ans+p*M(pin Z))

    那么对于前k个方程构成的方程组,我们就是要求一个正整数q,使得(ans+q*M equiv a_k(mod b_k)).

    移项得(q*M equiv a_k-ans(mod b_k))

    如果你理解了扩展欧几里得算法的话,看到上面这个式子应该会感到很亲切.

    我们令(c=a_k-ans),则我们要求的就是(q*M equiv c(mod b_k)),即求出(gcd=exgcd(M,b_k,x,y)),如果gcd不是c的约数,则该方程无解,则整个同余方程组无解.

    若方程有解,则(x*(c/gcd))就是方程(q*M equiv c(mod b_k))的解,则前i个方程构成的方程组的解就是(ans+[x*(c/gcd)]*M).

    综上我们只要跑k次扩展欧几里得就行了.然后洛咕上这道题相乘的时候会爆long long,要用到龟速乘.

    #include<bits/stdc++.h>
    #define rg register
    #define LL long long 
    using namespace std;
    inline LL read(){
        rg LL s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    LL n,a[100005],b[100005];
    inline LL exgcd(LL a,LL b,LL &x,LL &y){
        if(b==0){x=1;y=0;return a;}
        LL d=exgcd(b,a%b,y,x);
        y-=x*(a/b);
        return d;
    }
    inline LL quickmul(LL a,LL b,LL c){//龟速乘
        LL cnt=0;
        while(b){
    		if(b&1)cnt=(cnt+a)%c;
    		a=(a+a)%c;
    		b>>=1;
        }
        return cnt%c;
    }
    inline LL ex_intchina(){//模板
        LL ans=a[1],M=b[1];
        for(int i=2;i<=n;i++){
    		LL c=((a[i]-ans)%b[i]+b[i])%b[i];
    		LL x,y,gcd=exgcd(M,b[i],x,y);
    		if(c%gcd!=0)return -1;
    		x=quickmul(x,c/gcd,b[i]);
    //当前第i个方程的解
    		ans+=x*M;
    //更新前i个方程组的解ans
    		M*=b[i]/gcd;
    //更新M(所有模数的最小公倍数)
    		ans=(ans%M+M)%M;
        }
        return ans;
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
    		b[i]=read();a[i]=read();
        }//转换一下输入,我习惯b[i]是模数
        printf("%lld
    ",ex_intchina());
        return 0;
    }
    
    
  • 相关阅读:
    软件创意——汽车语音安全系统
    对系统管理岗位的理解。
    求二维数组最大子数组的和。郭林林&胡潇丹
    电梯调度 结对项目开发(郭林林&胡潇丹)
    电梯调度 结对项目开发
    电梯调度 结对项目开发
    电梯调度的设计与实现过程(李帅 张硕)
    敏捷软件方法综述
    二维数组的子数组和最大问题(李帅 张硕)
    求数组子数组和的最大值 (线性算法)
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10547175.html
Copyright © 2020-2023  润新知