Codevs1732-矩阵乘法快速幂
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codevs1732-矩阵乘法快速幂相关的知识,希望对你有一定的参考价值。
Codevs1732,这道题要求求fibonacci数列的第N项,1 <= n <= 100000000000000,非常大,普通的O(N)的求法肯定会TLE,所以我们需要用的快速幂矩阵乘法,在O(logN)的时间内即可求出。
矩阵的乘法是这样的:
我们定义X(i,j)表示矩阵第i行第j列的元素。
我们定义两个矩阵A和B,A有n行m列,B有m行p列,则此时矩阵A和B的乘法有定义(当且仅当A的列数=B的行数时,A*B有定义):
A*B=C,矩阵C为n行p列 ,C(i,j)=Σ(A(i,k)*B(k,j)),1<=k<=m。矩阵的乘法可以这样用程序表达:
struct Matrix{ qint A[10][10]; int m,n; //表示该矩阵有m行n列 friend Matrix operator * (const Matrix a,const Matrix b){ Matrix ret; ret.m=a.m,ret.n=b.n; for(int i=0;i<a.m;i++){ for(int j=0;j<b.n;j++){ ret.A[i][j]=0; for(int k=0;k<b.m;k++){ret.A[i][j]=(ret.A[i][j]+a.A[i][k]*b.A[k][j])%MOD;} } } return ret; } };
矩阵的乘法有结合律但没有交换律,即(A*B)*C等于A*(B*C),但是A*B不等于B*A。由于矩阵的乘法支持结合律,所以可以利用快速幂的思想在O(logN)的时间内求出矩阵A ^ N。矩阵可以很好的表示线性递推关系。例如:
f(n)=a1*f(n-1) + a2*f(n-2) + ······ + ad*f(n-d),则我们可以设矩阵:
F(N)=|f(n-d+1) | ( 共d行1列)
| ······ |
| f(n-1) |
| f(n) |
我们再设矩阵A=
|0,1,0 ······ 0|
|0,0,1 ······ 0|
| ····················· |
|0,0,0 ······ 1|
|a1,a2,····ad|
(共d行d列),
则存在下列关系A*F(N-1)=F(N)。
于是我们就可以通过计算A的幂来快速求F(N)了。
贴一个codevs1732的标程:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 using namespace std; 5 typedef long long qint; 6 const int MOD=1000000007; 7 struct Matrix{ 8 qint A[10][10]; 9 int m,n;//m行n列的矩阵 10 friend Matrix operator * (const Matrix a,const Matrix b){ 11 Matrix ret; 12 ret.m=a.m,ret.n=b.n; 13 for(int i=0;i<a.m;i++){ 14 for(int j=0;j<b.n;j++){ 15 ret.A[i][j]=0; 16 for(int k=0;k<b.m;k++){ 17 ret.A[i][j]=(ret.A[i][j]+a.A[i][k]*b.A[k][j])%MOD; 18 } 19 } 20 } 21 return ret; 22 } 23 }; 24 25 int get_ans(qint n){ 26 if(n<=1) return n; 27 n=n-1; 28 bool f=true; 29 Matrix st,now,pow; 30 31 st.A[0][0]=0,st.A[1][0]=1; 32 st.m=2,st.n=1; 33 34 pow.A[0][0]=0,pow.A[0][1]=1; 35 pow.A[1][0]=1,pow.A[1][1]=1; 36 pow.m=2,pow.n=2; 37 38 while(n>0){ 39 if(n & 1){ 40 if(f){now=pow;f=false;} 41 else{now=now*pow;} 42 } 43 pow=pow*pow; 44 n=n>>1; 45 } 46 47 now=now*st; 48 return now.A[1][0]; 49 } 50 51 52 53 int main(){ 54 qint n; 55 while(scanf("%lld",&n)!=EOF){ 56 printf("%d\n",get_ans(n)); 57 } 58 59 return 0; 60 }
1msAC,各种爽。
以上是关于Codevs1732-矩阵乘法快速幂的主要内容,如果未能解决你的问题,请参考以下文章
codevs1281 矩阵乘法 快速幂 !!!手写乘法取模!!! 练习struct的构造函数和成员函数