1.中国剩余定理回顾:
这个问题源自于我国数学古书《孙子算经》中的一道问题:“今有物,不知其数,三三数之,剩二;五五数之,剩三;七七数之,剩二。问物几何?”意思是一个整数除以三余二,除以五余三,除以七余二,求这个整数(满足条件且最小)。
做法是:
n%3==2,n%5==3,n%7==2,并且3,5,7折三个数是互质的。
我们找到使(5*7*a)%3==1的数:(5*7*a)=70;
我们找到使(3*7*b)%5==1的数:(5*7*b)=21;
我们找到使(3*5*c)%7==1的数:(3*5*c)=15
那么(70×2+21×3+15×2) % (3×5×7) = 23, 23即是答案。
理解如下:
70×2 = 140,当中的2是指n%3 = 2的2,因为70%3=1,乘2后使其能满足%3=2的条件。(毕竟题目要求的是%3==2的,而不是%3==1的,但是我们可以在求得%3==1得基础上扩大倍数,求得%3==2的)
同理, 21×3使其能满足%5=3,15×2使其能满足%7=2 又70能整除5和7,21能整除3和7,15能整除3和5 因此70×2+21×3+15×2 = 233能满足%3=2,%5=3,%7=2的条件 将233对3×5×7=105取模,是为了取得最小的情况,因为105是能够同时整除3,5,7的数,如果减去,对该数满足%3=2,%5=3,%7=2没有影响。因此对105取模,得到的结果便是最小并满足条件的数。
这里的中国剩余定理必须要求除数是互质的,但是有些题目的同余方程式除数并不互质,那么将不能使用传统的中国剩余定理。
2.题意:
人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。
3.解析:
找到使(23×28)的公倍数模33得1的数,答案是1288
找到使(23×33)的公倍数模28得1的数,答案是14421|
找到使(28×33)的公倍数模23得1的数,答案是5544
(5544×p+14421×e+1288×i) % (23×28×33) = ans + d
4.代码:
#include <iostream>
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
int md[3]={23,28,33};
int re[3];
int d;
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int ans=exgcd(b,a%b,x,y);
int temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
int China_Remainder(int md[],int re[])
{
int lcm=1;
int d,x,y,m,sum=0;
for(int i=0;i<3;i++)
lcm=lcm*md[i];
for(int i=0;i<3;i++)
{
m=lcm/md[i];
d=exgcd(md[i],m,x,y);
sum=(sum+y*m*re[i])%lcm;
}
return (lcm+sum%lcm)%lcm;
}
int main()
{
int cnt=1;
while(~scanf("%d%d%d%d",&re[0],&re[1],&re[2],&d))
{
if(re[0]==-1||re[1]==-1||re[2]==-1||d==-1)
break;
int num=China_Remainder(md,re);
if(num==0) num=21252;
else if(num<0)
num=num+21252;
printf("Case %d: the next triple peak occurs in %d days.\n",cnt++,num-d);
}
return 0;
}
一开始就套用的中国剩余定理的模板,结果WA。 AC代码如下:
#include <iostream>
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
int md[3]={23,28,33};
int re[3];
int main()
{
int p,e,i,d;
int cnt=1;
while(~scanf("%d%d%d%d",&p,&e,&i,&d))
{
if(p==-1||e==-1||i==-1||d==-1)
break;
int lcm=21252;
int num=(5544*p+14421*e+1288*i-d+21252)%21252;
if(num==0)
num=21252;
printf("Case %d: the next triple peak occurs in %d days.\n",cnt++,num);
}
}
5.参考