韩信点兵的故事大家一定都听说过,韩信让士兵分别3个3个报数多2人,5个5个报数多4人,7个7个报数多6人,通过每次报数的余数计算出军队的人数。
其实,韩信所做的,就是解了三个同余方程:
x≡2 (mod 3)
x≡4 (mod 5)
x≡6 (mod 7)
怎么解呢?古人想了一个聪明的办法:
找一个数x1,使得它是5和7的倍数,而除3余2,
找一个数x1,使得它是7和3的倍数,而除5余4,
找一个数x1,使得它是5和3的倍数,而除7余6,
然后三个数加起来,就一定满足这个条件,而且解周期为3*5*7
中国剩余定理
我们把这个算法拓展,对于任意的方程组x≡bi (mod mi)
即:
x≡b1 (mod m1)
x≡b2 (mod m2)
x≡b3 (mod m3)
......
x≡bn (mod mn)
其中m都是互质的
那么我们对于每一个方程,算出一个xi,使得xi满足:xi≡1 (mod mi) 且xi≡0 (mod mj)【j!=i】
也就是说xi是其他m的倍数,而模mi余1
y*(N/mi)≡1 (mod mi) 【N=m1*m2*m3*......mn】用扩展欧几里得算法就可以解出了
那么最终的x=(x1*b1+x2*b2+x3*b3+......xn*bn) mod N 【N=m1*m2*m3*......mn】
【我懒就先不打代码了= =】
水题:POJ1006
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long int using namespace std; const int maxn=100005,INF=2000000000,P=1000000007; void exgcd(int a,int b,int& d,int& x,int& y){ if(!b) {d=a;x=1;y=0;} else exgcd(b,a%b,d,y,x),y-=(a/b)*x; } int main(){ int N=21252,A[4],T[4]={0,23,28,33},t,ans=0,cnt=0; while(cin>>A[1]>>A[2]>>A[3]>>t){ if(t==-1) break; ans=0; cnt++; for(int i=1;i<=3;i++){ int x,y,a=T[i],b=N/T[i],d; exgcd(a,b,d,x,y); ans=(ans+y*b*A[i])%N; } ans=((ans-t)%N+N)%N; if(!ans) ans+=N; printf("Case %d: the next triple peak occurs in %d days. ",cnt,ans); } return 0; }