大神養成中.....
阿新 • • 發佈:2019-02-04
昨天晚上矩陣小王子給我們講了一下矩陣快速冪,學習了一下,寫了一個模板。
1:思想
矩陣快速冪的思想就是跟數的快速冪一樣,假如我們要求2^11,次方,我們可以把 11 寫成 1+2+8 ,也就是2^0 + 2^1 + 2^3 。那麼把一個O(n)的時間複雜度降到了log(n)
矩陣快速冪的思想和數的快速冪是一模一樣的,就是要自己實現矩陣的乘法,然後可以套數的快速冪的模板。
2:難點
矩陣題目的難點在於構造矩陣,一般用於有能夠推出遞推式的題目,推出遞推式之後,發現遞推O(n)的複雜度時間比較大,那麼我們可以構造一個矩陣,然後用矩陣快速冪降低到log(n)的時間複雜度
給出這樣一個遞推式
f(x)=a*f(x-2)+b*f(x-1)+c
然後求f(n),n為10^9
這樣直接遍歷的時間複雜度肯定是不允許的那麼我們就想辦法構造一個矩陣]
| a , 1 , 0| | a , 1 , 0|^(n-2)
|F(n) , F(n-1) ,1 | = | F(n-1) , F(n-2) ,1 | * | b , 0 , 0| = | f2 ,f1 , 1| *| b , 0 , 0|
|c , 0 , 1 | |c , 0 , 1 |
那麼我們就可以直接用矩陣快冪了。
快速冪模板:
#include <cstdio> #include <string> #include <cmath> #include <iostream> using namespace std; const long long M = 1000007; const long long N = 3; long long t,b,c,f1,f2; struct Node //矩陣 { long long line,cal; long long a[N+1][N+1]; Node(){ line=3,cal=3; a[0][0] = b; a[0][1] = 1; a[0][2] = 0; a[1][0] = t; a[1][1] = 0; a[1][2] = 0; a[2][0] = c; a[2][1] = 0; a[2][2] = 1; } }; Node isit(Node x,long long c) //矩陣初始化 { for(long long i=0;i<N;i++) for(long long j=0;j<N;j++) x.a[i][j]=c; return x; } Node Matlab(Node x,Node s) //矩陣乘法 { Node ans; ans.line = x.line,ans.cal = s.cal; ans=isit(ans,0); for(long long i=0;i<x.line;i++) { for(long long j=0;j<x.cal;j++) { for(long long k=0;k<s.cal;k++) { ans.a[i][j] += x.a[i][k]*s.a[k][j]; ans.a[i][j]=(ans.a[i][j]+M)%M; } } } return ans; } long long Fast_Matrax(long long n) //矩陣快速冪 { if(n==1) return f1; n-=2; long long x=1,f=n,ok=1; Node ans,tmp,ch; ans.line = 1,ans.cal = 3; ans.a[0][0] = f2, ans.a[0][1] = f1 ,ans.a[0][2] = 1; while(n>0) { if(n%2) { ans=Matlab(ans,tmp); } tmp=Matlab(tmp,tmp); n/=2; } return ans.a[0][0]; } int main() { long long n,T; scanf("%lld",&T); while(T--) { scanf("%lld%lld%lld%lld%lld%lld",&f1,&f2,&t,&b,&c,&n); printf("%lld\n",Fast_Matrax(n)); } return 0; }