昨天晚上矩阵小王子给我们讲了一下矩阵快速幂,学习了一下,写了一个模板。
1:思想
矩阵快速幂的思想就是跟数的快速幂一样,假如我们要求2^11,次方,我们可以把 11 写成 1+2+8 ,也就是2^0 + 2^1 + 2^3 。那么把一个O(n)的时间复杂度降到了log(n)
矩阵快速幂的思想和数的快速幂是一模一样的,就是要自己实现矩阵的乘法,然后可以套数的快速幂的模板。
2:难点
矩阵题目的难点在于构造矩阵,一般用于有能够推出递推式的题目,推出递推式之后,发现递推O(n)的复杂度时间比较大,那么我们可以构造一个矩阵,然后用矩阵快速幂降低到log(n)的时间复杂度
比如说nyoj 301
给出这样一个递推式
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; }