《算法竞赛进阶指南》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; }
证明:
每一个不曾起舞的日子,都是对生命的辜负。