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
第一反应递归,但是n可能是一个很大的值,这时候,资源就不够了,所以还是要找到其他的解题途径。
注意到:每一个f(n),只会受到f(n-1)跟f(n-2)的影响,所以。当连续的两个f值与之前任意的连续的两个f值重复的话,就说明后面肯定是一样的了。
如:a,b,……c,d,a,b……可以知道a,b……c,d肯定是一个循环节(可能不是最小的循环节)。接下来看看最长的循环有多长。模7运算,只有可能出现0~6这7个数,这样连续的两个数值对共有7*7=49种。又每个由于可能会有f(1),f(2)与f(2),f(3)对应相等的情况,故总共48位数就可以容下这49种情况了。这49种情况是最理想的状态,相互间的取值互不干扰的。一般情况下,循环节的长度都是要比48小的。所以可以只计算前个48f值,存下来,然后我们试着寻找循环周期的长度,它的开始位置,最后可以按要求的输出。
#include <stdio.h>
int main()
{
int A,B,flag,period,i,j;
int n,index;
int fn[48];
while(scanf("%d %d %ld",&A,&B,&n)!=EOF)
{
if(A==0&&B==0&&n==0)
break;
index = n-1;
fn[0] = 1;
fn[1] = 1;
flag = 0;
for(int t=2;t<48;t++)
{//算前48位
fn[t] = (A*fn[t-1] + B*fn[t-2])%7;
}
for(i=0;i<46;i++)
{//比较每连续的两位
for(j=i+1;j<48;j++)
{
if(fn[i]==fn[j]&&fn[i+1]==fn[j+1])
{//找到了重复的连续两位
flag = 1;
break;
}
}
if(flag==1)
{
period = j-i;
break;
}
}
if(index>=48)
index = (index-i) % period;
printf("%d\n",fn[index]);
}
return 0;
}
这样写无法通过,是wrong answer
在网上看到了一些帖子,都说要这么写
#include <stdio.h>
int main()
{
int A,B,flag,period,i,j;
int n,index;
int fn[48];
while(scanf("%d %d %ld",&A,&B,&n)!=EOF)
{
if(A==0&&B==0&&B==0)
break;
index = n-1;
fn[0] = 1;
fn[1] = 1;
flag = 0;
for(int t=2;t<48;t++)
{
fn[t] = (A*fn[t-1] + B*fn[t-2])%7;
}
index = index % 48;
printf("%d\n",fn[index]);
}
return 0;
}
果然ac了。
但是,这样的就表示48是所有情况下的循环节的公倍数,而且这种循环都是以1,1两个连续数开头的,是这样吗?
这个是A=1,B=5的情况,我手算了一遍,跟程序的结果对比了一下,发现周期是21,48不可能是它的倍数。在n=49的时候,ac的那个程序给出的是1,也就是f(1)的结果,而我原本写的那个是0,二者不一样,肯定有一个是错的。
核对之前的数列,可以确定我的结果的正确性。因此,可以确定这道题测试数据有问题。