Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 111285 | Accepted: 34638 |
Description
Input
Output
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
题目大意:
人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值,在这一天,人在相应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。如今给出三个日期,分别相应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天開始,算出最少再过多少天后三个峰值同一时候出现。
解题思路:
首先化简一下问题:欲求从某天開始,算出再过多少天后三个峰值同一时候出现,设要求的这个值为ans
假设我们能找到一天,三个峰值同一时候出现,我们记这天为 x ,再记 体力,情感,智力出现峰值的日期 分别为 a,b,c ,起始日期为 d.
那么必定:满足条件 x=a+23*t1=b+28*t2=c+33*t2.
再看一下 ans 与 x 的关系:ans = ( x - d ) % (23*28*33) ,所以求出 x 就能够了。
求X要用到 中国剩余定理
【转】自:点击打开链接
在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。详细解法分三步:
我们将“孙子问题”拆分成几个简单的小问题,从零開始,试图揣測古人是怎样推导出这个解法的。
首先,我们如果n1是满足除以3余2的一个数,比方2,5,8等等,也就是满足3*k+2(k>=0)的一个随意数。相同,我们如果n2是满足除以5余3的一个数,n3是满足除以7余2的一个数。
有了前面的如果,我们先从n1这个角度出发,已知n1满足除以3余2,能不能使得 n1+n2 的和仍然满足除以3余2?进而使得n1+n2+n3的和仍然满足除以3余2?
这就牵涉到一个最基本数学定理,假设有a%b=c,则有(a+kb)%b=c(k为非零整数),换句话说,假设一个除法运算的余数为c,那么被除数与k倍的除数相加(或相减)的和(差)再与除数相除,余数不变。这个是非常好证明的。
以此定理为根据,假设n2是3的倍数,n1+n2就依旧满足除以3余2。同理,假设n3也是3的倍数,那么n1+n2+n3的和就满足除以3余2。这是从n1的角度考虑的,再从n2,n3的角度出发,我们可推导出下面三点:
因此,为使n1+n2+n3的和作为“孙子问题”的一个终于解,需满足:
所以,孙子问题解法的本质是从5和7的公倍数中找一个除以3余2的数n1,从3和7的公倍数中找一个除以5余3的数n2,从3和5的公倍数中找一个除以7余2的数n3,再将三个数相加得到解。在求n1,n2,n3时又用了一个小技巧,以n1为例,并不是从5和7的公倍数中直接找一个除以3余2的数,而是先找一个除以3余1的数,再乘以2。
这里又有一个数学公式,假设a%b=c,那么(a*k)%b=a%b+a%b+…+a%b=c+c+…+c=kc(k>0),也就是说,假设一个除法的余数为c,那么被除数的k倍与除数相除的余数为kc。展开式中已证明。
最后,我们还要清楚一点,n1+n2+n3仅仅是问题的一个解,并非最小的解。怎样得到最小解?我们仅仅须要从中最大限度的减掉掉3,5,7的公倍数105就可以。道理就是前面讲过的定理“假设a%b=c,则有(a-kb)%b=c”。所以(n1+n2+n3)%105就是终于的最小解。
解题代码:
#include <iostream> #include <cstdio> using namespace std; int a,b,c,d; int n1,n2,n3; void get(){//get n1,n2,n3 for(int i=1;;i++){ if(28*33*i%23==1){ n1=28*33*i; break; } } for(int i=1;;i++){ if(23*33*i%28==1){ n2=23*33*i; break; } }for(int i=1;;i++){ if(23*28*i%33==1){ n3=23*28*i; break; } } } int main(){ get(); int casen=0; while(scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF){ if( a==-1 && b==-1 && c==-1 && d==-1) break; int ans=(n1*a+n2*b+n3*c-d)%(23*28*33); ans=ans<=0?ans+23*28*33:ans; printf("Case %d: the next triple peak occurs in %d days.\n",++casen,ans); } return 0; }