矩陣優化遞推數列
阿新 • • 發佈:2019-02-20
Problem
求斐波那契數列第n項,輸出答案模10^9+7的值(n<2^63)
Prepare
(對於學過線代的大佬請跳至Solution)
我們先介紹一下矩陣,我們表現形式就是二維陣列。而矩陣相對於二維陣列不同的是具有乘法運算。
對於n*m的矩陣a和m*p的矩陣b,表示a*b的矩陣c是n*p的,其中矩陣c的第i行j列的元素滿足
舉個栗子,如下:
順便指一下,對於n*n的矩陣,唯一存在這個矩陣a,使得對於任意矩陣b,a*b=b,其中a的主對角線上所有數為1,其他數為0
如果還是看不懂,百度百科
Solution
對於斐波那契數列f(n)滿足f(n)=f(n-1)+f(n-2)(廢話!)
我們構造矩陣a,使得:
所以,我們可以通過計算a^n來得到答案,誒,這不是也要O(n)時間嗎?別忘了還有快速冪(kasumi),和普通整數的求冪大抵相差不了多少。
Code
#include<cstdio> #include<cstring> #define MOD 1000000007 using namespace std; typedef long long LL; struct Matrix { int n; LL a[2][2]; Matrix():n(2){memset(a,0,sizeof(a));} Matrix operator*(const Matrix& mat){ Matrix res; for(int i=0;i<n;i++) for(int j=0;j<mat.n;j++) for(int k=0;k<n;k++) res.a[i][j]=(a[i][k]*mat.a[k][j]%MOD+res.a[i][j])%MOD; return res; } Matrix operator=(const Matrix& mat){memcpy(a,mat.a,sizeof(a));} }; Matrix kasumi(Matrix d,LL k){ Matrix ans; for(int i=0;i<ans.n;i++) ans.a[i][i]=1; while(k){ if(k&1) ans=ans*d; d=d*d; k>>=1; } return ans; } int main(){ Matrix d; LL n; scanf("%lld",&n); d.a[0][0]=d.a[0][1]=d.a[1][0]=1; printf("%lld",kasumi(d,n).a[1][0]); }