杭电ACM1005-Number Sequence
来源:互联网 发布:淘宝卖情趣内衣怎么样 编辑:程序博客网 时间:2024/06/01 11:44
杭电ACM1005-Number Sequence
这所谓的水题又给了我一次惨痛的教训。
转载自:http://czs646967.lofter.com/post/14a7e2_418db0
Problem Description
A number sequence is defined as follows:
f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
Given A, B, and n, you are to calculate the value of f(n).
Input
The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed.
Output
For each test case, print the value of f(n) on a single line.
Sample Input
1 1 3
1 2 10
0 0 0
Sample Output
2
5
思路:
第一眼看给出的f(n)公式,
f(1) = 1, f(2) = 1,
f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
第一个联想到的是斐波那契数列,但是题目说了1 <= A, B <= 1000, 1 <= n <= 100,000,000
这里的n相当大,不适合直接去求f(n)。
留意到mod7,这意味着f(n)的取值范围被控制在0-6这7种情况,由此想到的就是f(n)是否存在一个循环的数列。
下面就是要得出这题核心的两个结论:
1.如何找出循环?
平时找循环一般是罗列出前面几个,但是这里只列出前几位的f(n)还不够的。
因为我们还不知道这个循环大概有多大。
在来看这个式子,f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7,
f(n - 1)和f(n - 2)也都和f(n)一样,范围会在0-6.
注意这里的A、B是我们输入的值,所以在这里要看做常量。
我们可以看出f(n)的值与 f(n - 1)和f(n - 2)直接相关的。
而 f(n - 1)和f(n - 2)一共有7*7=49种可能的组合。
所以这里的第一个重要结论,函数f(n)的循环会在这个49的范围以内。
2.如何找出它的循环结点?
当输入的A、B值不同,这个循环的结点也不同。
注意f(1) = 1, f(2) = 1, 是两个特殊的情况。
在上一个结论的基础上,可以发现,
当 f(n - 1)=1和f(n - 2)=1时就代表一个循环的重新开始,这是第二个重要结论。
下面这段是我起先没能AC的代码:
#include<stdio.h>int main(){int a,b,f[50],i;long int n;f[0]=f[1]=1;while(scanf("%d%d%d",&a,&b,&n)&&(a||b||n)){if(n<3){printf("1\n");continue;}for(i=2;;i++){f[i]=(a*f[i-1]+b*f[i-2])%7;if(f[i]==1&&f[i-1]==1)break;} i-=1;printf("%d\n",f[(n-1)%i]);}return 0;}
代码的思路跟前面的分析差不多,用f[50]的数组记录f(n),找出循环结点即可。
这里我用数组f[0]开始存储f(1),使得代码的后半部分显得不太清晰。
这段代码的结论是对的,
AC不出来的原因,就是我所受的又一教训了。
这个循环语句:for(i=2;;i++),
我故意没有给这个for语句设置判断条件,平时的习惯。
这个循环是通过if(f[i]==1&&f[i-1]==1)情况的break来跳出的。
但是正因为这点,杭电一直给我WA,这里加上判断条件即可。
下面还有个小细节,
f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7可以稍作变形
变成f(n) = (A mod7* f(n - 1) + B mod7* f(n - 2)) mod 7
把mod带到里面,我们可以对A、B进行简化。
代码中可以加上A=A%7;B=B%7;
但是因为这里的A、B的最大取值只有1000,所以对于这里的实际运算速度影响很小。
下面是最终AC出来的代码:
#include<stdio.h>int main(){int a,b,n,i;int f[50];f[1]=f[2]=1;while(scanf("%d %d %d",&a,&b,&n)&&(a||b||n)){for(i=3;i<50;i++){f[i]=(a*f[i-1]+b*f[i-2])%7;if(f[i]==1&&f[i-1]==1)break;} n=n%(i-2);f[0]=f[i-2];printf("%d\n",f[n]);}return 0;}
- 杭电acm1005 Number Sequence
- 杭电ACM1005-Number Sequence
- 杭电ACM1005,解决!
- 杭电ACM1005
- 杭电ACM1005
- 杭电acm1005
- 杭电ACM1005
- 杭电acm1005
- [杭电]Number Sequence
- 杭电ACM1005(矩阵乘法)
- 杭电ACM1005 C做法
- 杭电1005 Number Sequence
- 杭电1711 Number Sequence
- 杭电 1711 Number Sequence
- 杭电 1005 Number Sequence
- 杭电 1005 Number Sequence
- 杭电1005 Number Sequence
- 杭电1005Number Sequence
- 单词搜索树
- BOM案例之图片移动
- 解决Linux环境Oracle显示乱码
- 无线安全专题_攻击篇--MAC泛洪攻击
- 解决MySQL主从复制不一致的情况
- 杭电ACM1005-Number Sequence
- SQL Server锁介绍及死锁原因(转)
- VS断点调试技巧
- 如何开启慢日志
- 字符串之统计字符串
- js判断是pc端还是移动端
- iOS多线程学习之GCD详解
- 推送相关
- Cocos Creator中使用动作系统(官方文档摘录)