POJ 1006 Biorhythms

太水了,考完试就忘记剩余定理- -!

这道题完全就是考你中国剩余定理

 (中国剩余定理CRT)设m1,m2,...,mk是两两互素的正整数,即gcd(mi, mj) =1, i≠j, i,j = 1,2,...,k

  则同余方程组:
  x≡b1 (mod m1)
  x≡b2 (mod m2)
  ...
  x≡bk (mod mk)
  模[m1,m2,...,mk]有唯一解,即在[m1,m2,...,mk]的意义下,存在唯一的x,满足:
  x≡bi mod [m1,m2,...,mk], i = 1,2,...,k

这里谈谈我自己的理解,就是通过不断的构造,Mi*(m/mi)=1(mod mi)

这个就是数论中求一个数关于mod的逆,具体可以参考有关数论的书

其中Mi*mi = m,m就是所有mi的乘积。。注意哦,这里各个mi必须互素,不然就失效。(如果不互素怎么办?那就化作互素呗,有兴趣可以参考数论的相关教材)

然后解就是ans = M1*m/m1*b1+M2*m/m2*b2……  (mod  m)    

怎么理解最后一个式子呢,你想想。最后一个式子是不是mod mi都是bi。

为什么呢?因为对于每一项Mj*m/mj,(1<=j<=n)除了i=j外,其他的项mod mi都是零,结果决定于第i项,但是第i项一定等于bi的,因为我们的Mi*(m/mi)=1 (mod mi)

代码如下:

其中求每一个mi关于Mi的逆用扩展欧几里得定理!!!

Mi = m/mi,m = m1*m2*m3...mn;

#include<iostream>
#include<cstdio>
using namespace std;
int m1 = 23,m2=28,m3=33,m=m1*m2*m3;
int M1,M2,M3;
int exGcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
int r = exGcd(b, a % b, x, y);
int t = x;
x = y;
y = t - a / b * y;
return r;
  }


void solve()//求出孙子定理中各个因子的逆
{
int y;
exGcd(m1,m/m1,y,M1);
while(M1<0)M1+=m1;
exGcd(m2,m/m2,y,M2);
while(M2<0)M2+=m2;
exGcd(m3,m/m3,y,M3);
while(M3<0)M3+=m3;
// printf("%d %d %d\n",M1,M2,M3);
// printf("%d %d %d\n",m1*M1,M2*m2,M3*m3);
}
int main()
{
solve();
int n;
//scanf("%d",&n);
int casenum = 0;
while(1){
int p,d,i,e;
scanf("%d%d%d%d",&p,&e,&i,&d);
if(p==-1 && e==-1 && i==-1 && d==-1)break;
int ans = M1*m/m1*p+M2*m/m2*e+M3*m/m3*i;
ans%=m;
if(ans-d>0)
printf("Case %d: the next triple peak occurs in %d days.\n",++casenum,ans-d);
else
printf("Case %d: the next triple peak occurs in %d days.\n",++casenum,ans-d+m);
}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值