杭电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;
}