矩阵快速幂详解

介绍:

矩阵乘法定义自行看百度

矩阵快速幂顾名思义,就是把多次矩阵乘法用快速幂的形式算出,一般常用于递推的优化;

做法:

如果是裸的矩阵快速幂,做法非常简单,先定义一个数组记录矩阵的每个数值,在做快速幂(快速幂中相应的乘用矩阵乘法代替);

相关题目:

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 }
posted @ 2018-08-08 09:00  DFSlover  阅读(2147)  评论(4编辑  收藏  举报

Contact with me