Biorhythms
http://poj.org/problem?id=1006
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 97029 | Accepted: 29832 |
Description
Input
Output
Case 1: the next triple peak occurs in 1234 days.
Use the plural form ``days'' even if the answer is 1.
Sample Input
0 0 0 0 0 0 0 100 5 20 34 325 4 5 6 7 283 102 23 320 203 301 203 40 -1 -1 -1 -1
Sample Output
Case 1: the next triple peak occurs in 21252 days. Case 2: the next triple peak occurs in 21152 days. Case 3: the next triple peak occurs in 19575 days. Case 4: the next triple peak occurs in 16994 days. Case 5: the next triple peak occurs in 8910 days. Case 6: the next triple peak occurs in 10789 days.
Source
(n+d)%23=p; //这里的p(以及下面的e,i)应该使小于23(28, 33)的,可数据并不是这么回事,疑问呐???????
(n+d)%28=e;
(n+d)%33=i ,求n 。
这道题用到的是近世代数里面讲过的中国剩余定理。这里就说点题外话,关于中国剩余定理的来历:
民间传说着一则故事——“韩信点兵”。
秦朝末年,楚汉相争。一次,韩信将1500名将士与楚王大将李锋交战。苦战一场,楚军不敌,败退回营,汉军也死伤四五百人,于是韩信整顿兵马也返回大本营。当行至一山坡,忽有后军来报,说有楚军骑兵追来。只见远方尘土飞扬,杀声震天。汉军本来已十分疲惫,这时队伍大哗。韩信兵马到坡顶,见来敌不足五百骑,便急速点兵迎敌。他命令士兵3人一排,结果多出2名;接着命令士兵5人一排,结果多出3名;他又命令士兵7人一排,结果又多出2名。韩信马上向将士们宣布:我军有1073名勇士,敌人不足五百,我们居高临下,以众击寡,一定能打败敌人。汉军本来就信服自己的统帅,这一来更相信韩信是“神仙下凡”、“神机妙算”。于是士气大振。一时间旌旗摇动,鼓声喧天,汉军步步进逼,楚军乱作一团。交战不久,楚军大败而逃。
在一千多年前的《孙子算经》中,有这样一道算术题:
“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”按照今天的话来说:一个数除以3余2,除以5余3,除以7余2,求这个数.
这样的问题,也有人称为“韩信点兵”.它形成了一类问题,也就是初等数论中解同余式.这类问题的有解条件和解的方法被称为“中国剩余定理”,这是由中国人首先提出的.
好,我们言归正传,是不是发现我们要求的方程组和孙子算经历的方程组非常大相似?
一般地,中国剩余定理是指若有一些两两互质的整数,则以下联立同余方程组对模 有唯一解:
孙子算经中的计算过程总结出来应该如下表示:
因为n%3=2,n%5=3,n%7=2且3,5,7互质 使5×7被3除余1,用35×2=70; (这个称为35相对于3的数论倒数) 使3×7被5除余1,用21×1=21; 使3×5被7除余1,用15×1=15。
(70×2+21×3+15×2)%(3×5×7)=23
同样我们可以得到本体的计算过程:
使33×28被23除余1,用33×28×8=5544; 使23×33被28除余1,用23×33×19=14421;
使23×28被33除余1,用23×28×2=1288。 (5544×p+14421×e+1288×i)%(23×28×33)=n+d
n=(5544×p+14421×e+1288×i-d)%(23×28×33)
当然为了节省提交程序所运行的时间,我们可以预先写个小程序把这三个数论倒数预先求出来,然后再程序里直接应用结果就可以了。
#include<stdio.h> #define N (23*28*33) int p,e,i,d; int main(){ int a=0,b=0,c=0; while(a%23!=1) a+=28*33; while(b%28!=1) b+=23*33; while(c%33!=1) c+=23*28; int cases=0; while(scanf("%d %d %d %d",&p,&e,&i,&d)){ if(p==-1 && e==-1 && i==-1 && d==-1) break; int ans=(p*a+e*b+i*c-d)%N; if(ans<=0) ans+=N; printf("Case %d: the next triple peak occurs in %d days.\n",++cases,ans); } return 0; }