介紹:
矩陣乘法定義自行看百度;
矩陣快速冪顧名思義,就是把多次矩陣乘法用快速冪的形式算出,一般常用於遞推的優化;
做法:
如果是裸的矩陣快速冪,做法非常簡單,先定義一個數組記錄矩陣的每個數值,在做快速冪(快速冪中相應的乘用矩陣乘法代替);
相關題目:
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 }
