题意:已知f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7,给出A,B,n,求f(n)
题解:n巨大,循环肯定超时,在模7的条件下,0<=f(n)<=6,一共7种选择,则f(n-1)和f(n-2)各有7种选择,共49种组合,至少在第50个组合必定会和前面的重复,找出循环节。
坑:不知网上为什么都说找连续两个1的循环节,有大神指出这是错误的,当a和b是某两个数时,序列是1,4,6循环,但我忘记是哪两个数了,也找不到博客。
在我看来,两重循环找出相同的比较稳妥,而不是找两个1。
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; int a,b,n; int f[10086]; int main()///hdu1005 { while(scanf("%d %d %d",&a,&b,&n)!=EOF&&(a+b+n)) { memset(f,0,sizeof(f)); f[1]=f[2]=1; int i,j; int minn=min(n,100); for(i=3;i<=minn;i++) f[i]=(a*f[i-1]+b*f[i-2])%7; ///找第一次和第二次出现的循环节 int cha=-1; for(i=3;i<=minn;i++) { for(j=i+1;j<=minn;j++)///不吝啬这点时间找出循环节 if( f[i]==f[j] && f[i+1]==f[j+1] ) { cha=j-i;///循环节的差 break; } if(cha!=-1) break; } /// 此时i是循环节的起点 int idx; if(cha==-1)///数据太少,没有找到循环节,直接求 { idx=n; } else { n=n+cha; idx=(n-2)%cha; if(idx==0) idx=2+cha; else idx=2+idx; } printf("%d ",f[idx]); } return 0; }