中国剩余定理

韩信点兵的故事大家一定都听说过,韩信让士兵分别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;
}



原文地址:https://www.cnblogs.com/Mychael/p/8282877.html