http://acm.hdu.edu.cn/showproblem.php?pid=1005
1.一开始就注意到了n的数据范围 <=100 000 000,但是还是用普通的循环做的,自然TLE了,然后朴素打表,= =运行不了,(怎么可能能把数组开到那么大)。再然后就想到了寻找下一个1 1 连续在一起的,那就能开始下一轮循环了。
但是,各种WA……(将数组开大一点,寻找到a[ i ] = a[ i -1 ] ==1 即跳出),这个AC代码将102改成100,150,200都可以,但是108,49 ,204什么的就不行。
其实也可能数组并不是从11开始循环的,而是后面出现了两组相邻相同的非1 1数,循环则从最先出现两组相邻对等的数开始循环。如1 1 …………X X…………X X…………然后循环就从XX开始循环,不关1 1什么事儿了,但是下面这个代码却能AC而且数组的长度(maxn)有一定限制,有些能有些不能(???)。
#include <cstdio> #include <iostream> #define maxn 102 using namespace std; int num[maxn]; int main() { int a,b,n,i=3; num[0]=1; num[1]=1; num[2]=1; while(~scanf("%d%d%d",&a,&b,&n),a||b||n) { i=3; for(i=3;i<maxn;i++) { num[i]=(a*num[i-1]+b*num[i-2])%7; if(num[i]==1&&num[i-1]==1) break; } num[0]=num[i-2]; n%=i-2; cout << num[n] << endl; } return 0; }
然后就看有说fn =fn-1 + fn-2 再对7取模,其中的f 项都是0 - 6 之间的数,所以 两数相加之和再取模,最多有7*7种可能后必定会fn-1 与 fn-2 的值的情况与前面的有重复,所以循环节为49 ,这感觉是最容易接受也最为合理的一种解释。
然后就有了如下AC代码,其中maxn为48,49均可(???)。
#include <cstdio> #include <iostream> #define maxn 48 using namespace std; int num[maxn]; int main() { int a,b,n,i=3; num[0]=1; num[1]=1; num[2]=1; while(~scanf("%d%d%d",&a,&b,&n),a||b||n) { i=3; for(i=3;i<=maxn;i++) { num[i]=(a*num[i-1]+b*num[i-2])%7; /*if(num[i]==1&&num[i-1]==1) { //cout << i << endl; break; }*/ } num[0]=num[maxn]; cout << num[n%maxn] << endl; } return 0; }
再然后就是矩阵快速幂了,占坑,(回来学= =)。
最后贴个暴力代码(网上搜的,这个厉害了= =),一个个试,找到他们不同的A,B下他们的周期的最小公倍数为1008。
#include<iostream> using namespace std; int main() { int a,b,n,i; while(scanf("%d%d%d",&a,&b,&n)&&a&&b&&n) { int f[1009]; f[1]=1; f[2]=1; for(i=3;i<=1008;i++) { f[i]=(a*f[i-1]+b*f[i-2])%7; } printf("%d\n",f[(n-1)%1008+1]); } return 0; }
以上为做了耗了我几个小时的hdu1005(不知道值不值= =)。
未解之谜……待续。