在POJ上有译文(原文右上角),选择语言:简体中文
求解同余方程组:
x=ai(mod mi) i=1~r, m1,m2,...,mr互质
利用中国剩余定理
令M=m1*m2*...*mr,Mi=M/mi
因为mi两两互质,所以(Mi,mi)=1
令Mi*yi=1(mod mi)的解为yi,即Mi模mi的逆元
则方程的解为:
(a1*M1*y1+a2*M2*y2+...+ar*Mr*yr)%M
方法一:用扩展欧几里德求逆元
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; const int M=21252; int a[3],m[3]={23,28,33}; int sp,se,si,d; 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 tmp=x; x=y; y=tmp-a/b*y; return d; } int main() { int cases=0,ans; int ni[3],Mi[3],x,y; //因为mi是固定的,所以可以先将对应的逆元用扩展欧几里德求出来 for(int i=0;i<3;i++){ Mi[i]=M/m[i]; exgcd(Mi[i],m[i],x,y); ni[i]=x; } while(scanf("%d%d%d%d",&sp,&se,&si,&d)!=EOF){ if(sp==-1) break; a[0]=sp;a[1]=se;a[2]=si; ans=0; for(int i=0;i<3;i++){ ans=(ans+(a[i]*Mi[i]%M)*ni[i]%M)%M; ans=(ans+M)%M; } if(ans<=d){ ans=ans+M-d; } else ans=ans-d; printf("Case %d: the next triple peak occurs in %d days. ",++cases,ans); } return 0; }
方法二:枚举求Mi*yi
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int M=21252; int m[3]= {23,28,33}; int a[3]; int sp,se,si,d; int Mii[3],Mi[3]; int value; //求最大公约数,最小公倍数则两数相乘除以它们的最大公约数 int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } int main() { int cases=0; Mii[0]=Mi[0]=m[1]*m[2]; Mii[1]=Mi[1]=m[0]*m[2]; Mii[2]=Mi[2]=m[0]*m[1]; //枚举求Mi*yi for(; Mii[0]%m[0]!=1; Mii[0]+=Mi[0]) { } for(; Mii[1]%m[1]!=1; Mii[1]+=Mi[1]) { } for(; Mii[2]%m[2]!=1; Mii[2]+=Mi[2]) { } while(scanf("%d%d%d%d",&sp,&se,&si,&d)!=EOF) { if(sp==-1) break; a[0]=sp; a[1]=se; a[2]=si; value=((Mii[0]*a[0]+Mii[1]*a[1]+Mii[2]*a[2])%M+M)%M; int ans; if(value<=d) { ans=value+M-d; } else ans=value-d; printf("Case %d: the next triple peak occurs in %d days. ",++cases,ans); } return 0; }