首先将题目变成以下方程组,相当于要求这个同余方程的最小解
(n+d)%23 = p; -> x%23 = p;
(n+d)%28 = e; -> x%28 = e;
(n+d)%33 = i; -> x%33 = i;
另 M = 23*28*33 M1 = 28*33 M2 = 23*33 M3 = 23*28
若 M1*y1 % 23 = 1; -> M1*y1*p % 23 =p;
M2*y2 % 28 = 1; -> M2*y2*e % 28 =e;
M3*y3 % 33 = 1; -> M3*y3*i % 33 =i;
因为 M2 和 M3均为 23 的倍数 ,故( M1*y1*p + M2*y2*e + M3*y3*i )%23 = p;
因为 M1 和 M3均为 28 的倍数 ,故( M1*y1*p + M2*y2*e + M3*y3*i )%28 = e;
因为 M1 和 M2均为 33 的倍数 ,故( M1*y1*p + M2*y2*e + M3*y3*i )%33 = i;
所以 (M1*y1*p + M2*y2*e + M3*y3*i )是满足这个方程的一个解, 因为 23 38 33 都是素数,所以最小解为 (M1*y1*p + M2*y2*e + M3*y3*i )% M
y1 y2 y3用代码里面的gcd函数算出,相当于数 x% =z 已知 y、z 求x 的一个过程
数字小一点可以口算,这儿的数字太大了,等以后研究一下
参考: http://www.cnblogs.com/walker01/archive/2010/01/23/1654880.html
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
typedef long long LL;
static const int pCycleDays = 23;
static const int eCycleDays = 28;
static const int iCycleDays = 33;
void gcd(LL a, LL b, LL &d, LL &x, LL &y)
{
if(!b)
{
d = a, x = 1, y = 0;
}
else
{
gcd(b, a %b, d, y, x);
y -= x * (a/b);
}
}
LL inv(LL a, LL n)
{
LL d, x, y;
gcd(a,n,d,x,y);
return d == 1 ? (x + n) % n : -1;
}
int main()
{
int p,e,i,d;
int pFix, eFix, iFix;
int M = pCycleDays*eCycleDays*iCycleDays;
int M1 = eCycleDays*iCycleDays;
int M2 = pCycleDays*iCycleDays;
int M3 = pCycleDays*eCycleDays;
int t1 = inv(M1,pCycleDays);
int t2 = inv(M2,eCycleDays);
int t3 = inv(M3,iCycleDays);
int count = 0;
while(cin>>p>>e>>i>>d)
{
if(p == -1 && e == -1 && i == -1 && d == -1)
break;
count ++;
int nCommonPeak = (t1*M1*p + t2*M2*e + t3*M3*i - d)%M ;
if(nCommonPeak <= 0)
nCommonPeak += M;
char trace[200];
sprintf(trace,"Case %d: the next triple peak occurs in %d days.",count,nCommonPeak);
printf("%s\n",trace);
}
return 0;
}