NYOJ 314 解题报告
来源:互联网 发布:c语言temp 编辑:程序博客网 时间:2024/06/05 10:53
斐波那契数列四吧
- 描述
斐波那契数列为:0,1,1,2,3,5,8,13....,常规递推公式为f(n)=f(n-1)+f(n-2);
但这里不一样的是,我们的前两个数字不一定是0,1;
也就是说,斐波那契数列的前两个数字是随机数(保证是非负整数)。下面我们开始吧,我会告诉你斐波那契数列的第20项的值m,请你判断是否会有这样的数列存在。
对了,你要保证数列的每一项都是整数哦
- 输入
- 第一行呢,按照惯例我们输入一个数字N,表示测试数据组数。
接下来肯定就有N行了。。
每行包含一个整数m(m<10000000),表示数列的第20项的值。 - 输出
- 如果存在这样的数列呢,输出该数列的第一项和第二项的值
else 输出“No answer”
每组数据输出后换行。 - 样例输入
11000000
- 样例输出
154 144
这里有一点需要注意,f(1)=1而非题目中的那个0,因为按题目的意思,f(0)=0。
首先根据斐波那契数列的递推公式从F(20)开始倒推,F(20)=F(19)+F(18),而F(19)=F(18)+F(17),F(18)=F(17)+F(16),得出F(20)=3F(17)+2F(16),然后一直迭代下去:F(20)=8F(15)+5F(14), F(20)=21F(13)+13F(12),F(20)=55F(11)+34F(10),F(20)=144F(9)+89F(8),F(20)=377F(7)+233F(6),F(20)=987F(5)+610F(4),F(20)=2584F(3)+1597F(2),有没有发现前面的系数也是斐波那契数列的项呢?最后一步,由F(3)=F(2)+F(1)得F(20)=4181F(2)+2584F(1)。这个式子能够帮助我们由第20项推出第1、2两项。
所以,这道题归根结底就是求解丢番图方程1597x+2584y=f(20)的最小正整数解。这里,gcd(1597, 2584)=1一定能整除f(20),即1 | f(20)。我是这样思考的,首先根据扩展的欧几里得算法求得这个方程的一组特解。
扩展的欧几里得算法是这样的,找到一组整数s, t使得a*s+b*t=c。实现它是使用一个递归。递归的终止条件是gcd(a,b)*1+b*0=gcd(a,b)。因此需要不停地使用欧几里得算法的步骤来找出s和t前面的一系列系数。先看一下代码:
long long Extend_Euclid(long long *s,long long *t,long long a,long long b){if(b==0){*s=1;*t=0;return a;}long long ans=Extend_Euclid(s,t,b,a%b);long long temp=(*s);*s=*t;*t=temp-(a/b)*(*t);return ans;}
函数的返回值是s前面的系数。
而后面的几句赋值语句的意思是,将后一步得出的t值赋值给s,再将后一步得出的s和t得到的s-[a/b]*t赋值个t。这是为什么呢?因为gcd(a, b)=s*rj+t*r(j-1),而欧几里得算法里rj=r(j-2)-r(j-1)*q(j-1),代入有gcd(a, b)=(t-s*q(j-1))*r(j-1)+s*r(j-2)。最后r0=a,r1=b。
但是现在得到的s和t值又可能是有负数的,所以还要根据通解x=x0+(b/gcd(a, b))*n,y=y0-(a/gcd(a, b))*n一步步寻找使得x, y均大于0的一组解,而且这个一定是最小的正整数解。如果找不到,就表明No Answer。
最终代码如下:
#include <stdio.h>long long Extend_Euclid(long long *s,long long *t,long long a,long long b){if(b==0){*s=1;*t=0;return a;}long long ans=Extend_Euclid(s,t,b,a%b);long long temp=(*s);*s=*t;*t=temp-(a/b)*(*t);return ans;}int main(){int N;scanf("%d",&N);long long s,t;Extend_Euclid(&s,&t,2584,4181);while(N--){long long m,x,y;int flag=0;scanf("%lld",&m);x=m*s,y=m*t;while(x<0||y<0) { if(x<0) { x=x+4181; y=y-2584; if(x>=0&&y<0) { flag=1; printf("No answer\n"); break; } } else { x=x-4181; y=y+2584; if(y>=0&&x<0) { flag=1; printf("No answer\n"); break; } } } if(flag==0) printf("%lld %lld\n",x,y);}return 0;}
再来看看标程,简单粗暴,直接上枚举。而且在某些情况下,直接枚举比我的程序运行时间更短!
#include <stdio.h>int main(){int m,n;scanf("%d",&m);while(m--){scanf("%d",&n);int flag=0;for(int i=0;i*4181<=n;++i){if((n-i*4181)%2584==0) {printf("%d %d\n",(n-i*4181)/2584,i);flag=1;break;}}if(flag==0) printf("No answer\n");}return 0;}
- NYOJ 314 解题报告
- NYOJ解题报告~
- NYOJ 46 解题报告
- NYOJ 1 解题报告
- NYOJ 458 解题报告
- NYOJ 541 解题报告
- NYOJ 362 解题报告
- NYOJ 570 解题报告
- NYOJ 520 解题报告
- NYOJ 998 解题报告
- NYOJ 865 解题报告
- NYOJ-263解题报告
- NYOJ-833解题报告
- NYOJ 10 Skiing 解题报告
- NYOJ 448 寻找最大数 解题报告
- NYOJ 448 寻找最大数 解题报告
- NYOJ 84 阶乘的0 解题报告
- NYOJ 455题 解题报告-黑色帽子
- OBS (open boardcast server)结构分析
- linux中的硬连接和软连接
- Visual Studio 调试小技巧(1)-根据字符串内容添加断点
- STL源码剖析----list
- 浅谈大型web系统架构
- NYOJ 314 解题报告
- About php Extensions
- COD测定仪 新任东风公司董事长竺延风调研东风康明斯 _ 行业新闻 _ 行业资讯 _ 中国专用汽车网(专汽之都)
- verilog中阻塞和非阻塞的区别
- 感觉快到了不惑的年龄了
- Android控件——ToggleButton
- Trie树(字典树)HDU——1251
- select、poll、epoll之间的区别总结[整理]
- bzoj3043: IncDec Sequence 差分