題目
Winder最近在學習fibonacci 數列的相關知識。我們都知道fibonacci數列的遞推公式是F(n)=F(n-1)+F(n-2)(n>=2 且n 為整數)。 Winder想知道的是當我們將這個遞推式改為F(n)=AF(n-1)+BF(n-2)(n>=2且n為整數)時我們得到的是怎樣的數列。但是,Winder很懶,所以只能由你來幫他來完成這件事。 注意,這里我們依然令F(0)=F(1)=1。
★數據輸入
輸入第一行三個正整數N,A 和B(N<=10;1<=A、B<=100 且均為整數)。 接下來有N 行,每行一個自然數n(n<=100000000)。
★數據輸出
輸出一行一個整數F(n),由於結果可能會很大,Winder要求輸出結果對2013取模。
輸入示例 | 輸出示例 |
5 4 5 2 4 8 16 32 |
9 209 1377 182 9 |
題解:
一道很經典的矩陣快速冪裸題。
首先講解快速冪,當我們需要求$a^{b}$對mod取模時,可以將b轉化為2進制,就可以將b轉換為若干個二次冪之和。例如,我們在計算2的12次方時,12的二進制為1100,1100中的兩個1的位權分別為4和8,因此$2^{12}$次方便可以轉換為$2^{4}*2^{8}$。由此,我們先將答案ans賦值為1,只需要計算a的1,2,4,8.....次方,然后看一下b在該位的數值是否為1即可,如果為1,將ans乘上即可。
快速冪的代碼如下
ll fastpow(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; }
接下來回到本題,由於n的數字較大,加上取模速度較慢,本題遞歸遞推會超時。因此需要尋找復雜度小於O(n)的算法。
由於
$
\left(
\begin{matrix}
a & b \\
1 & 0
\end{matrix}
\right)*
\binom{f(n)}{f(n-1)}=\binom{f(n+1)}{f(n)}
$我們可以構造矩陣,可以得到
$$
\left(
\begin{matrix}
a & b \\
1 & 0
\end{matrix}
\right) \tag{2}^{n-1}*
\binom{f(1)}{f(0)}=\binom{f(n)}{f(n-1)}
$$
由此,我們只需要計算矩陣
$$
\left(
\begin{matrix}
a & b \\
1 & 0
\end{matrix}
\right)
$$
的n-1次方即可,對於這個矩陣的n-1次方,使用快速冪求出所求矩陣,便可以在$\log n$的時間內計算出f(n)的值。
#include<iostream>
#include<cstdio> #include<algorithm> #include<cmath> #include<cstdlib> #include<cstring> #include<string> #include<vector> #include<queue> #include<set> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair <int,int> pii; #define rep(i,x,y) for(int i=x;i<y;i++) #define rept(i,x,y) for(int i=x;i<=y;i++) #define per(i,x,y) for(int i=x;i>=y;i--) #define pb push_back #define fi first #define se second #define mes(a,b) memset(a,b,sizeof a) const int inf=0x3f3f3f3f; const int mod=2013; class matrix { public: int arrcy[6][6];//arrcy為矩陣,下表從0開始 int row,column;//row為矩陣的行,column為矩陣的列 friend matrix operator *(matrix s1,matrix s2) { int i,j; matrix s3; for (i=0;i<s1.row;i++) { for (j=0;j<s2.column;j++) { for (int k=0;k<s1.column;k++) { s3.arrcy[i][j]+=s1.arrcy[i][k]*s2.arrcy[k][j]; s3.arrcy[i][j]%=mod; } } } s3.row=s1.row; s3.column=s2.column; return s3; } }; matrix quick_pow(matrix s1,long long n)//矩陣快速冪函數,s1為矩陣,n為冪次 { matrix mul=s1,ans;
//將ans構造為單位矩陣 ans.row=ans.column=s1.row; memset(ans.arrcy,0,sizeof ans.arrcy); for(int i=0;i<ans.row;i++) ans.arrcy[i][i]=1; while(n) { if(n&1) ans=ans*mul; mul=mul*mul; n/=2; } return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n,a,b; cin>>n>>a>>b; matrix mul; mul.row=mul.column=2; mul.arrcy[0][0]=a; mul.arrcy[0][1]=b; mul.arrcy[1][0]=1; mul.arrcy[1][1]=0; matrix r; r.row=2; r.column=1; r.arrcy[0][0]=r.arrcy[1][0]=1; rep(i,0,n) { int x; cin>>x; if(!x)//當x=1時,x-1<0無法使用快速冪,答案為0,特判即可 { cout<<1<<endl; continue; } matrix mm=quick_pow(mul,x-1); mm=mm*r; cout<<mm.arrcy[0][0]<<endl; } return 0; }