杭电ACM1005-Number Sequence

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

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值