POJ 1006 Biorhythms
来源:互联网 发布:知乎珠帘寨主 编辑:程序博客网 时间:2024/06/05 21:15
这个是这个剩余定理,开始按同余方程的方法求,结果很快就出来了。
AC代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 21252using namespace std;int w[4],q[4]={23,28,33};void exgcd(int a,int b,int &d,int &x,int &y){ if(b==0) { d=a;x=1;y=0; return ; } else { exgcd(b,a%b,d,y,x); y-=x*(a/b); }}int main(){ int c,i,j,sum,lcm=1,n; int a,b,d,x,y; while(scanf("%d%d%d%d",&w[0],&w[1],&w[2],&n)) { sum=0; if(w[0]==-1 && w[1]==-1 && w[2]==-1 && n==-1) break; for(i=0;i<3;i++) { a=N/q[i]; b=q[i]; exgcd(a,b,d,x,y); sum=(sum+a*x*w[i])%N; } sum-=n; while(sum <= 0) sum+=N; printf("Case %d: the next triple peak occurs in %d days.\n",lcm++,sum); } return 0;}
后来,在百度的时候,对剩余定理有了新的了解。
要引入本题解法,先来看一个故事 “韩信点兵”:
传说西汉大将韩信,由于比较年轻,开始他的部下对他不很佩服。有一次阅兵时,韩信要求士兵分三路纵队,结果末尾多2人,改成五路纵队,结果末尾多3人,再改成七路纵队,结果又余下2人,后来下级军官向他报告共有士兵2395人,韩信立即笑笑说不对(因2395除以3余数是1,不是2),由于已经知道士兵总人数在2300~2400之间,所以韩信根据23,128,233,------,每相邻两数的间隔是105(3、5、7的最小公倍数),便立即说出实际人数应是2333人(因2333=128+20χ105+105,它除以3余2,除以5余3,除以7余2)。这样使下级军官十分敬佩,这就是韩信点兵的故事。
韩信点兵问题简化:已知 n%3=2, n%5=3, n%7=2, 求n。
再看我们这道题,读入p,e,i,d 4个整数
已知(n+d)%23=p; (n+d)%28=e; (n+d)%33=i ,求n 。
两道题是一样的。但是韩信当时计算出结果的?
韩信用的就是“中国剩余定理”,《孙子算经》中早有计算方法,大家可以查阅相关资料。
“韩信点兵”问题计算如下:
因为n%3=2, n%5=3, n%7=2 且 3,5,7互质 (互质可以直接得到这三个数的最小公倍数)
令x= n%3=2 , y= n%5=3 ,z= n%7=2
a, 使5×7×a被3除余1,有35×2=70,即a=2;
b, 使3×7×b被5除余1,用21×1=21,即b=1;
c, 使3×5×c被7除余1,用15×1=15, 即c=1。
那么n =(70 * x+21 * y+15 * z)%lcm(3,5,7) = 23 这是n的最小解
而韩信已知士兵人数在2300~2400之间,所以只需要n+i×lcm(3,5,7)就得到了2333,此时i=22
同样,这道题的解法就是:
已知(n+d)%23=p; (n+d)%28=e; (n+d)%33=i ;
a, 使33×28×a被23除余1,用33×28×8=5544;
b, 使23×33×b被28除余1,用23×33×19=14421;
c, 使23×28×c被33除余1,用23×28×2=1288。
因此有(5544×p+14421×e+1288×i)% lcm(23,28,33) =n+d
又23、28、33互质,即lcm(23,28,33)= 21252;
所以有n=(5544×p+14421×e+1288×i-d)%21252
本题所求的是最小整数解,避免n为负,因此最后结果为n= [n+21252]% 21252
那么最终求解n的表达式就是:
n=(5544*p+14421*e+1288*i-d+21252)%21252;
当问题被转化为一条数学式子时,你会发现它无比简单。。。。直接输出结果了。
AC代码:
#include <iostream>#include <cmath>#include <cstdio>#include <cstring>#define ant1 21252using namespace std;int main(){ int a,b,c,d,ant=1,sum; while(~scanf("%d%d%d%d",&a,&b,&c,&d)) { if(a==-1 && b==-1 &&c ==-1 && d==-1) break; sum=(5544*a+14421*b+1288*c-d+2*ant1)%ant1; if(sum==0) sum=ant1; printf("Case %d: the next triple peak occurs in %d days.\n",ant++,sum); } return 0;}
俩种方法的时间都是32ms,就是代码长度不同吧!!
路途中。。。
- poj 1006 Biorhythms
- poj 1006 Biorhythms
- poj 1006 Biorhythms
- POJ 1006 Biorhythms
- POJ 1006 Biorhythms
- POJ 1006 Biorhythms
- 【POJ】1006 Biorhythms
- POJ-1006:Biorhythms
- POJ 1006 Biorhythms
- POJ 1006 Biorhythms
- POJ 1006 Biorhythms
- poj 1006 Biorhythms
- POJ 1006 Biorhythms
- Poj 1006 Biorhythms
- POJ 1006 Biorhythms
- poj 1006 hdu1370 Biorhythms
- 【POJ】1006 Biorhythms
- poj 1006 Biorhythms
- window.location.hash属性介绍
- 算法理解——LCS算法(最长公共子序列)
- GNUPLOT使用技巧
- linux中使用head命令和tail命令查看文件中的指定行
- android 判断点击的位置是不是在指定的view上
- POJ 1006 Biorhythms
- JS的对象和数组的区别和使用
- android MotionEvent getX getRawX getScrollX 的区别
- matlab读取串口数据并显示曲线
- 异步获取在线图片
- js中typeOf用法
- 理解Lua语言中的__index,__newindex,rawget和rawset
- Android根据用户设置决定是否在开机时启动应用程序
- 【好书推荐】-你的灯亮着吗?