矩阵快速幂详解
介绍:
矩阵乘法定义自行看百度;
矩阵快速幂顾名思义,就是把多次矩阵乘法用快速幂的形式算出,一般常用于递推的优化;
做法:
如果是裸的矩阵快速幂,做法非常简单,先定义一个数组记录矩阵的每个数值,在做快速幂(快速幂中相应的乘用矩阵乘法代替);
相关题目:
1、【模板】矩阵快速幂
照上面的方法做就ok了;
注意刚开始ans数组要清成单位矩阵(任何矩阵乘它不变);
1 #include<cstdio> 2 using namespace std; 3 #define int long long 4 const int MAXN=101,MOD=1000000007; 5 int n,k,a[MAXN][MAXN],b[MAXN][MAXN],ans[MAXN][MAXN],c[MAXN][MAXN]; 6 //a数组用来记录每次的矩阵 7 //ans数组为记录答案的数组 8 //b作为一个暂时存放的数组 (不然每次直接更改a数组就会导致将更改过的数组相乘) 9 void ksm(int n,int m)//普通的快速幂 10 { 11 while(m>1) 12 { 13 for(int i=1;i<=n;++i) 14 for(int j=1;j<=n;++j) 15 b[i][j]=0; 16 if(m%2==1) 17 { 18 for(int i=1;i<=n;++i) 19 for(int j=1;j<=n;++j) 20 { 21 for(int k=1;k<=n;++k) 22 c[i][j]=(c[i][j]+ans[i][k]*a[k][j]%MOD)%MOD; 23 } 24 for(int i=1;i<=n;++i) 25 for(int j=1;j<=n;++j) 26 ans[i][j]=c[i][j],c[i][j]=0; 27 } 28 for(int i=1;i<=n;++i) 29 for(int j=1;j<=n;++j) 30 for(int k=1;k<=n;++k) 31 b[i][j]=(b[i][j]+a[i][k]*a[k][j]%MOD)%MOD; 32 for(int i=1;i<=n;++i) 33 for(int j=1;j<=n;++j) 34 a[i][j]=b[i][j]; 35 m=m/2; 36 } 37 for(int i=1;i<=n;++i) 38 for(int j=1;j<=n;++j) 39 { 40 for(int k=1;k<=n;++k) 41 c[i][j]=(c[i][j]+ans[i][k]*a[k][j]%MOD)%MOD; 42 } 43 for(int i=1;i<=n;++i) 44 for(int j=1;j<=n;++j) 45 ans[i][j]=c[i][j],c[i][j]=0; 46 } 47 main() 48 { 49 scanf("%lld%lld",&n,&k); 50 for(int i=1;i<=n;++i) 51 for(int j=1;j<=n;++j) scanf("%lld",&a[i][j]); 52 for(int i=1;i<=n;++i) 53 ans[i][i]=1; 54 ksm(n,k); 55 for(int i=1;i<=n;++i) 56 { 57 for(int j=1;j<=n;++j) 58 printf("%lld ",ans[i][j]%MOD); 59 printf("\n"); 60 } 61 return 0; 62 }
2、用矩阵快速幂优化的斐波那契数列
做法类似,斐波那契数列递推式为f[i]=f[i-1]+f[i-2];
由f[i-2] f[i-1]推出f[i-1] f[i],把两边都看成矩阵,$1 \times 2$的矩阵$ \times $$2 \times 2$的矩阵=$1 \times 2$的矩阵,所以稍稍推算就能算出需要的矩阵;
要求的f[n]=f[1]$ \times 矩阵 ^ n$;
接着就用矩阵快速幂求出答案;
1 #include<cstdio> 2 using namespace std; 3 #define int long long 4 const int MAXN=101,MOD=1000000007; 5 int n,k,a[MAXN][MAXN],ans[MAXN][MAXN],c[MAXN][MAXN]; 6 //a数组用来记录每次的矩阵 7 //ans数组为记录答案的数组 8 //b作为一个暂时存放的数组 (不然每次直接更改a数组就会导致将更改过的数组相乘) 9 void ksm(int m) 10 { 11 while(m>1) 12 { 13 if(m%2==1) 14 { 15 for(int i=1;i<=2;++i) 16 for(int j=1;j<=2;++j) 17 for(int k=1;k<=2;++k) 18 c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD; 19 for(int i=1;i<=2;++i) 20 for(int j=1;j<=2;++j) 21 ans[i][j]=c[i][j],c[i][j]=0; 22 } 23 for(int i=1;i<=2;++i) 24 for(int j=1;j<=2;++j) 25 for(int k=1;k<=2;++k) 26 c[i][j]=(c[i][j]+a[i][k]*a[k][j]%MOD)%MOD; 27 for(int i=1;i<=2;++i) 28 for(int j=1;j<=2;++j) 29 a[i][j]=c[i][j],c[i][j]=0; 30 m=m/2; 31 } 32 for(int i=1;i<=2;++i) 33 for(int j=1;j<=2;++j) 34 { 35 for(int k=1;k<=2;++k) 36 c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD; 37 } 38 for(int i=1;i<=2;++i) 39 for(int j=1;j<=2;++j) 40 ans[i][j]=c[i][j],c[i][j]=0; 41 } 42 main() 43 { 44 scanf("%lld",&n); 45 a[1][1]=0; 46 a[2][1]=1; 47 a[1][2]=1; 48 a[2][2]=1; 49 //求出的所需要的矩阵 50 for(int i=1;i<=2;++i) 51 ans[i][i]=1; 52 ksm(n-1); 53 printf("%lld",ans[2][2]%MOD); 54 return 0; 55 }
3、稍微变化的fibonacci
同理,找出f[i-3] f[i-2] f[i-1] 变为 f[i-2] f[i-1] f[i] 的矩阵;
再用矩阵快速幂;
1 #include<cstdio> 2 using namespace std; 3 #define int long long 4 const int MAXN=101,MOD=1000000007; 5 int n,k,a[MAXN][MAXN],ans[MAXN][MAXN],c[MAXN][MAXN],t; 6 //a数组用来记录每次的矩阵 7 //ans数组为记录答案的数组 8 //b作为一个暂时存放的数组 (不然每次直接更改a数组就会导致将更改过的数组相乘) 9 void ksm(int m) 10 { 11 while(m>1) 12 { 13 if(m%2==1) 14 { 15 for(int i=1;i<=3;++i) 16 for(int j=1;j<=3;++j) 17 for(int k=1;k<=3;++k) 18 c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD; 19 for(int i=1;i<=3;++i) 20 for(int j=1;j<=3;++j) 21 ans[i][j]=c[i][j],c[i][j]=0; 22 } 23 for(int i=1;i<=3;++i) 24 for(int j=1;j<=3;++j) 25 for(int k=1;k<=3;++k) 26 c[i][j]=(c[i][j]+a[i][k]*a[k][j]%MOD)%MOD; 27 for(int i=1;i<=3;++i) 28 for(int j=1;j<=3;++j) 29 a[i][j]=c[i][j],c[i][j]=0; 30 m=m/2; 31 } 32 for(int i=1;i<=3;++i) 33 for(int j=1;j<=3;++j) 34 { 35 for(int k=1;k<=3;++k) 36 c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD; 37 } 38 for(int i=1;i<=3;++i) 39 for(int j=1;j<=3;++j) 40 ans[i][j]=c[i][j],c[i][j]=0; 41 } 42 main() 43 { 44 scanf("%lld",&t); 45 for(int kk=1;kk<=t;++kk) 46 { 47 scanf("%lld",&n); 48 a[1][1]=0; 49 a[2][1]=1; 50 a[3][1]=0; 51 a[1][2]=0; 52 a[2][2]=0; 53 a[3][2]=1; 54 a[1][3]=1; 55 a[2][3]=0; 56 a[3][3]=1; 57 //求出的所需要的矩阵 58 for(int i=1;i<=3;++i) 59 ans[i][i]=1; 60 ksm(n-1); 61 printf("%lld\n",ans[3][3]%MOD); 62 for(int i=1;i<=3;++i) 63 for(int j=1;j<=3;++j) 64 ans[i][j]=0; 65 } 66 }