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).
OutputFor each test case, print the value of f(n) on a single line.
Sample Input
1 1 3 1 2 10 0 0 0Sample Output
2 5
题意非常简单,
但是过大的n使得我们不能从头到尾跑一遍。
第一想法就是找规律,一定是循环的,
但是a,b未知,很难建立周期长度和a,b的关系。
最开始打算朴素地从第一个开始找,直到找到有连续两位相同的就结束(因为第三项是由前两项决定的,前两项相同第三项一定相同),算出周期长度,然后算出来,但是一度没想明白,怕万一超时了,然而,当我看到网上一篇与这道题有关的题解时,
我发现我果然
想多了……
模7后,每个数只有7种可能,连续两个数的组合只有49种可能,因此连续51个数,共有50个连续二元有序数对,这样根据抽屉原理,必有两个有序数对相同,因此必定发生了循环,因此只要枚举到第51位就行了,此时记录下发生循环的起始位置和循环长度,最后对n取个模处理一下就可以了。
但是看到的题解里默认循环起始位置是第一个数,然后我和它的AC程序比较了一下,随机生成a,b,n=4,3,117时,对方那篇题解就在第49个数发生了问题,至于能AC,我想恐怕是RP爆发吧,可能是数据太弱了的缘故。
最后,附上我的代码
#include<cstdio>
#include<cstdlib>
#include<time.h>
int main()
{
srand(time(NULL));//大家可以自动忽略这一行,本来是为了随机函数进行比较的
int a,b,n,i,j,k,d;bool bo=false;
int f[100]={0};
int p[100]={0};
scanf("%d%d%d",&a,&b,&n);
while (a!=0&&b!=0&&n!=0) {
a=a%7;b=b%7;bo=false;
f[1]=1;f[2]=1;k=1;
for (i=3;i<60;i++)
{
f[i]=(a*f[i-1]+b*f[i-2])%7;
for (j=1;j<i-1;j++)
if (f[j]==f[i-1]&&f[j+1]==f[i]) {
bo=true;
k=j;
break;
}
if (bo) {
d=i-k-1;break;
}
}
printf("%d\n",f[(n-k)%d+k]);
scanf("%d%d%d",&a,&b,&n);
}
return 0;
}