洛谷——P1349 廣義斐波那契數列
阿新 • • 發佈:2017-10-18
分享 for iostream amp size alt 以及 hide pre
題目描述
廣義的斐波那契數列是指形如an=p*an-1+q*an-2的數列。今給定數列的兩系數p和q,以及數列的最前兩項a1和a2,另給出兩個整數n和m,試求數列的第n項an除以m的余數。
輸入輸出格式
輸入格式:
輸入包含一行6個整數。依次是p,q,a1,a2,n,m,其中在p,q,a1,a2整數範圍內,n和m在長整數範圍內。
輸出格式:
輸出包含一行一個整數,即an除以m的余數。
輸入輸出樣例
輸入樣例#1:1 1 1 1 10 7輸出樣例#1:
6
說明
數列第10項是55,除以7的余數為6。
我們來通過這個題講一下斐波那契數列怎麽用矩陣乘法來優化吧
我們知道對於斐波那契數列我們有這樣的遞推式:f[n]=f[n-1]+f[n-2]
通常情況下,我們計算f(n)的時間復雜度就是O(n)(分別計算f(1), f(2) ... f(n - 1)).
但是當n很大又或者還有其他處理的復雜度一疊加便會超時。
所以當n很大的時候,我們的遞推式便不起作用了,我們應該像一種辦法來優化一下這個遞推式,怎麽辦呢,我們看到這個式子有加,有乘,我們就一般會想到矩陣乘法(這時候就有人會問了,博主,你眼瞎啊,明明就是個加法的式子,你說他有乘法。。。)額、、對於這個問題,我們可以將上面的式子做一個小小的變形,將它變成f[n]=f[n-1]*1+f[n-2]*1, f[n-1]=f[n-1]*1+f[n-2]*0
我們在這個地方普及一下矩陣乘法優化遞推式的特征:形如f(n) = a1 * f(n - 1) + a2 * f(n - 2) + ... + ak * f(n - k)+c (c為常數)
然後我們可以將他組成這樣的一個矩陣
然後我們進行矩陣乘法
來,看看代碼:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define mod 100000000 using namespace std; int n; int read() {矩陣乘法優化斐波那契int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); return x*f; } struct Node { long long m[3][3]; Node(){memset(m,0,sizeof(m));} }mb,ans; int GCD(int a,int b) { if(b==0) return a; return GCD(b,a%b); } Node operator*(Node a,Node b) { Node c; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) c.m[i][j]=(c.m[i][j]%mod+a.m[i][k]*b.m[k][j]%mod)%mod; return c; } int main() { n=read();n--; mb.m[1][1]=mb.m[1][2]=mb.m[2][1]=1; ans.m[1][1]=ans.m[2][2]=1; while(n) { if(1&n) ans=ans*mb; mb=mb*mb;n>>=1; } cout<<ans.m[1][1]; return 0; }
對於這個式子,我們可以根據樸素的斐波那契的矩陣乘法的形式將式子推出來
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; long long q,p,a1,a2,n,mod; long long read() { long long x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); return x*f; } struct Node { long long m[3][3]; Node(){memset(m,0,sizeof(m));} }begin,ans; Node operator*(Node a,Node b) { Node c; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) c.m[i][j]=(c.m[i][j]%mod+(a.m[i][k]%mod*b.m[k][j]%mod)%mod)%mod; return c; } int main() { p=read(),q=read(),a1=read(),a2=read(); n=read(),mod=read();n-=2; ans.m[1][1]=a2,ans.m[1][2]=a1; begin.m[1][1]=p,begin.m[2][1]=q,begin.m[1][2]=1; while(n) { if(n&1) ans=ans*begin; begin=begin*begin; n>>=1; } if(n+2==1) cout<<ans.m[1][2]%mod; else cout<<ans.m[1][1]%mod; return 0; }
洛谷——P1349 廣義斐波那契數列