《算法竞赛进阶指南》0x33同余 扩展欧几里得解线性同余方程组

题目链接:http://poj.org/problem?id=2891

解线性同余方程组,由于模数不是互质的,不能用中国剩余定理,但是可以通过扩展gcd的方法求解,时间复杂度大约是O(nlogn),当只有两个方程的时候可以容易求出解x,将x的通解凝聚成新的

模线性方程,接下来不断输入,进行n-1次迭代,即将结果保存在x = m1(mod a1)中,然后求一个最小的解输出即可。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll n;

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 tmp=x;
    x=y;
    y=tmp-(a/b)*y;
    return gcd;
}

int main(){
    ll m1,a1,m2,a2;
    while(cin>>n){
        scanf("%lld%lld",&a1,&m1);
        bool flag=true;
        ll lcm=a1;//前n个a的最小公倍数 
        for(int i=2;i<=n;i++){//迭代,将每次的结果都保存到a1,m1中 
            scanf("%lld%lld",&a2,&m2);    
            ll k1=0,k2=0;
            ll gcd=exgcd(a1,a2,k1,k2);
            if(!flag)continue;
            if((m2-m1)%gcd)flag=false;
            k1=k1*(m2-m1)/gcd;//算出一个特解
            k1=(k1%(a2/gcd)+a2/gcd)%(a2/gcd);//求最小的正整数解 
            lcm=a1*a2/gcd;//计算新的lcm 
            m1+=k1*a1;//特解k1*a1+m1是两个方程合并之后的新的m1, 
            a1=lcm;//新的a1,进行下一轮迭代 
        }
        if(flag)printf("%lld\n",(m1%a1+a1)%a1);//最终的结果保存在m1中,x mod a1 = m1
        else puts("-1");
    }
    return 0;
}

证明:

 

 

 

 

 

 

 

posted @ 2020-06-23 17:37  WA自动机~  阅读(312)  评论(0编辑  收藏  举报