杭电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;}
0 0
原创粉丝点击