【洛谷P1962 斐波那契數列】矩陣快速冪+數學推導
來提供兩個正確的做法:
- 斐波那契數列雙倍項的做法(附加證明)
- 矩陣快速冪
一、雙倍項做法
在偶然之中,在百度中翻到了有關於斐波那契數列的詞條(ofollow,noindex" target="_blank">傳送門
),那麼我們可以發現一個這個規律$ \frac{F_{2n}}{F_{n}}=F_{n-1}+F_{n+1} $,那麼我就想到了是不是可以用這個公式實現類似於快速冪之類的東西:power(n,m)=power(n*n,m/2)m mod 2=0 power(n,m)=power(n*n,m/2)*n m mod 2=1
快速冪這個東西,是分成偶數情況和奇數情況,所以我們只是知道偶數想的計算公式,所以我們接下來要推導一下奇數項的遞迴式
\[ F_{2n}=F_{n}\times(F_{n-1}+F_{n+1})\]
\[ F_{2n+2}=F_{n+1}\times(F_{n}+F_{n+2})\]
那麼我們就是要從\(F_{2n}\) 和\(F_{2n+2}\) 推導求出\(F_{2n+1}\)
\[ F_{2n+1}=F_{2n+2}-F_{2n} \]
\[ F_{2n+1}=F_{n+1}\times(F_{n}+F_{n+2})-F_{n}*(F_{n-1}+F_{n+1}) \]
\[ F_{2n+1}=F_{n+1}\times F_{n}+F_{n+1}\times F_{n+2} - F_{n}\times F_{n-1}-F_{n}\times F_{n+1}\]
\[ F_{2n+1}=F_{n+1}\times F_{n+2}-F_{n}\times F_{n-1}\]
\[ F_{2n+1}=F_{n+1}\times(F_{n+1}+F_{n})-F_{n}\times(F_{n+1}-F_{n})\]
\[ F_{2n+1}={F_{n+1}}^2+{F_{n}}^2 \]
以上就是我們對於這個公式的推導
那麼我們就得到了
F[2n] = F[n+1]² - F[n-1]² = (2F[n-1] + F[n]) · F[n]
F[2n+1] = F[n+1]² + F[n]²
那麼,我們在寫一個map,那麼就可以不用全部都遞迴到底了,優化一下。
用map對映一下大數,對映到我們的答案上。
#include <bits/stdc++.h> using namespace std; const int Mod=1e9+7;//mod數 long long n; map<long long,long long> ma;//搞對映 inline long long work(long long x){ if(x==1||x==0)return 1;//邊界 if(ma.count(x))return ma[x];//count如果是返回1那麼就是這個答案已經在map中對映過了,0就是沒有 long long res=0,t=x/2; if(x&1) res=work(t)*(work(t-1)+work(t+1))%Mod;//公式2 else res=work(t)*work(t)%Mod+work(t-1)*work(t-1)%Mod;//公式1 return ma[x]=res; } int main() {//主程式 cin>>n; long long res=work(n-1)%Mod; cout<<res<<endl; return 0; }
注:這個程式的複雜度是也差不多是log(n),也是非常優的解法
二、矩陣乘法解法
這個解法應該是這一道題的正解。
我是一個蒟蒻,還是隻是初懂矩陣乘法的小白。
我就貼一下自己的程式碼,詳細的題解還是看一下別的大佬的題解。
#include <bits/stdc++.h> using namespace std; #define mod 1000000007 //Mod數 struct Matrix{//這個是矩陣的結構體 long long ma[2][2]; }; Matrix mul(Matrix A,Matrix B)//矩陣乘法 { Matrix C;//答案矩陣 C.ma[0][0]=C.ma[0][1]=C.ma[1][0]=C.ma[1][1]=0;//初始化 for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { for(int k=0;k<2;k++) { C.ma[i][j]=(C.ma[i][j]+A.ma[i][k]*B.ma[k][j])%mod; } } } return C; } Matrix pow_mod(Matrix A,long long n)//卡蘇米+矩陣乘法優化 { Matrix B; B.ma[0][0]=B.ma[1][1]=1; B.ma[0][1]=B.ma[1][0]=0; while(n) { if(n&1) B=mul(B,A); A=mul(A,A); n>>=1; } return B; } int main() { long long n; Matrix A; A.ma[0][0]=1;A.ma[0][1]=1; A.ma[1][0]=1;A.ma[1][1]=0;//初始的陣列 Matrix ans=pow_mod(A,n); printf("%lld\n",ans.ma[0][1]);//輸出答案 return 0; }