51nod 1126 求遞推序列的第N項
阿新 • • 發佈:2018-12-15
這道題是好幾個月前周賽做的,當時敲了很久的矩陣快速冪,結果打完別人告訴我可以用打表做……
因為每一項都只由前兩項決定,所以我們不妨用(f[n-2],f[n-1])來表示f[n]。如果(f[n-2],f[n-1])這個狀態在之前出現過那麼後面一定就會重複前面的迴圈。而前兩項只有7*7=49種,所以最多50項開始就會出現迴圈,並且週期的上界是49。
但是網上能搜到的打表題解基本都是錯的,我當時找了不少都能被hack掉,因為這道題資料實在是太水了……我打表的做法改了很多次,每次都能AC但是對拍還是會拍出錯誤。
網上打表的做法主要錯誤有兩個:
1迴圈到49項就退出迴圈。好吧其實我根本不知道為什麼他們要在49之後退出迴圈。(f[n-2],f[n-1])最多有49種可能,但這並不代表到了49沒有找到週期週期就是49。
2找到週期t後認為答案是f[n%t]。這也是我犯過的錯誤。數列有周期並不代表第一項一定在週期裡,可能是從某一項開始才開始迴圈。比如對於某組a,b可能x->(y->z->y->z...)
我的做法是用一個used陣列來記錄出現過的(f[n-2],f[n-1]),並且用一個變數start來記錄迴圈開始的位置,最後的答案就是f[(n-start)%t + start],這個做法對拍了很久應該是沒有問題的了。
#include<bits/stdc++.h> using namespace std; int main() { int used[7][7]; int n,a,b; cin >> a >> b >> n; if(n==1||n==2){ cout << 1 << endl; return 0; } int f[100],t,start; memset(used,0,sizeof(used)); f[1]=f[2] = 1; for(int i = 3;;i++) { f[i] = (a*f[i-1]+b*f[i-2])%7; f[i] = (f[i]+7)%7; if(!used[f[i]][f[i-1]])used[f[i]][f[i-1]] = i; else { t = i - used[f[i]][f[i-1]]; start = used[f[i]][f[i-1]]; break; } } cout << f[(n-start)%t + start] << endl; }