矩阵快速幂

有些话、适合烂在心里 提交于 2020-03-06 03:32:27

矩阵是种神奇的东西,无奈我这种数学渣对于他的理解只能是表面。

快速幂应该都很熟悉,实际上把快速幂里面的乘法换成矩阵乘法就可以变为矩阵快速幂

上份模板:

 1 typedef vector<int>vec;
 2 typedef vector<vec>mat;
 3 typedef long long ll;
 4 mat mul(mat &A,mat &B){
 5     mat C (A.size(),vec(B[0].size()));
 6     for(int i=0;i<A.size();++i){
 7         for(int k=0;k<B.size();++k){
 8             for(int j=0;j<B[0].size();++j){
 9                 C[i][j]=(C[i][j]+(A[i][k]*B[k][j])%mod)%mod;
10             }
11         }
12     }
13     return C;
14 }
15 mat pow(mat A,ll n){
16     mat B (A.size(),vec(A.size()));
17     for(int i=0;i<A.size();++i)B[i][i]=1;
18     while(n>0){
19         if(n&1)B = mul(B,A);
20         A = mul(A,A);
21         n>>=1;
22     }
23     return B;
24 }
View Code

矩阵快速幂有什么作用呢?优化递推关系!!!!

先看一下求第n项费布那切数列f[n]=f[n-1]+f[n-2]

这样我们就可以快速的求得第n项

3734

题意:用红蓝绿黄去涂n个块,问红绿都为偶数块的方案数

假设当前前i个已经涂完其中红绿都为偶数有ai种,一奇一偶为bi,都为奇为ci ,那么对于i+1 有

a(i+1)=2*a(i)+b(i)

b(i+1)=2*a(i)+2*b(i)+2*c(i)

c(i+1)=b(i+1)+2*c(i)

这样就转化为求a(n)了

利用矩阵快速幂可以很好的解决。

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <set>
 5 #include <algorithm>
 6 #include <map>
 7 #include <queue>
 8 #include<cmath>
 9 #include<vector>
10 #define maxn 50010
11 #define maxm 100010
12 #define mod 10007
13 #define INF 0x3f3f3f3f
14 using namespace std;
15 typedef vector<int>vec;
16 typedef vector<vec>mat;
17 typedef long long ll;
18 mat mul(mat &A,mat &B){
19     mat C (A.size(),vec(B[0].size()));
20     for(int i=0;i<A.size();++i){
21         for(int k=0;k<B.size();++k){
22             for(int j=0;j<B[0].size();++j){
23                 C[i][j]=(C[i][j]+(A[i][k]*B[k][j])%mod)%mod;
24             }
25         }
26     }
27     return C;
28 }
29 mat pow(mat A,ll n){
30     mat B (A.size(),vec(A.size()));
31     for(int i=0;i<A.size();++i)B[i][i]=1;
32     while(n>0){
33         if(n&1)B = mul(B,A);
34         A = mul(A,A);
35         n>>=1;
36     }
37     return B;
38 }
39 int n;
40 void solve(){
41     mat A(3,vec(3));
42     A[0][0]=2;A[0][1]=1;A[0][2]=0;
43     A[1][0]=2;A[1][1]=2;A[1][2]=2;
44     A[2][0]=0;A[2][1]=1;A[2][2]=2;
45     A = pow(A,n);
46     printf("%d\n",A[0][0]);
47 }
48 int main (){
49     int t;
50     scanf("%d",&t);
51     while(t--){
52         scanf("%d",&n);
53         solve();
54     }
55 }
View Code

3420

题意:给你一个4*n的方格,问用1*2的去填有多少种方案。

这里给出Matrix67大神的一篇博客点我

里面的问题九就是这样一个问题,主要还是转移矩阵的构造,对于行数比较小的情况我们可以自己手动推,也更有助于理解。

但是实际上可以通过计算机来计算这个转移的矩阵,有点类似DFA。

我们只需要给他转移的规则就可以构造出这个矩阵(记忆化搜索)具体的看代码吧

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <set>
 5 #include <algorithm>
 6 #include <map>
 7 #include <queue>
 8 #include<cmath>
 9 #include<vector>
10 #define maxn 50010
11 #define maxm 100010
12 #define INF 0x3f3f3f3f
13 using namespace std;
14 typedef vector<int>vec;
15 typedef vector<vec>mat;
16 typedef long long ll;
17 int mod;
18 mat mul(mat &A,mat &B){
19     mat C (A.size(),vec(B[0].size()));
20     for(int i=0;i<A.size();++i){
21         for(int k=0;k<B.size();++k){
22             for(int j=0;j<B[0].size();++j){
23                 C[i][j]=(C[i][j]+(A[i][k]*B[k][j])%mod)%mod;
24             }
25         }
26     }
27     return C;
28 }
29 mat pow(mat A,ll n){
30     mat B (A.size(),vec(A.size()));
31     for(int i=0;i<A.size();++i)B[i][i]=1;
32     while(n>0){
33         if(n&1)B = mul(B,A);
34         A = mul(A,A);
35         n>>=1;
36     }
37     return B;
38 }
39 int n;
40 int dp[17][17];
41 void dfs(int i,int s){
42     if(dp[i][s]==1)return;
43     dp[i][s]=1;
44     for(int k=0;k<4;++k){
45         if(k<3&&!(s&(1<<k))&&!(s&(1<<(k+1)))){
46             dfs(i,s+(1<<k)+(1<<(k+1)));
47         }
48     }
49 }
50 void solve(){
51     memset(dp,0,sizeof(dp));
52     for(int i=0;i<(1<<4);++i)dfs(i,(1<<4)-1-i);
53     mat A(16,vec(16));
54     mat I(16,vec(16));
55     for(int i=0;i<16;++i){
56         for(int j=0;j<16;++j){
57             if(i==j)I[i][j]=1;
58             else I[i][j]=0;
59             A[i][j]=dp[i][j];
60            // cout<<A[i][j]<<" ";
61         }
62         //cout<<endl;
63     }
64     A = pow(A,n+1);
65     A  = mul(I,A);
66     printf("%d\n",A[15][0]);
67 }
68 int main (){
69     int t;
70     while(scanf("%d%d",&n,&mod)!=EOF){
71         if(mod==0&&n==0)break;
72         solve();
73     }
74 }
View Code

3233

题意给你矩阵A 求sum(A^0+A^1+...+A^k)%m

有了这个就可以直接搞了。实际上有更快的算法,基本原理就是Matrix里面写的

A^1+A^2+...+A^6 = (A^1+A^2+A^3)+A^3* (A^1+A^2+A^3)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <set>
 5 #include <algorithm>
 6 #include <map>
 7 #include <queue>
 8 #include<cmath>
 9 #include<vector>
10 #define maxn 50010
11 #define maxm 100010
12 #define INF 0x3f3f3f3f
13 using namespace std;
14 typedef vector<int>vec;
15 typedef vector<vec>mat;
16 typedef long long ll;
17 int mod;
18 mat mul(mat &A,mat &B){
19     mat C (A.size(),vec(B[0].size()));
20     for(int i=0;i<A.size();++i){
21         for(int k=0;k<B.size();++k){
22             for(int j=0;j<B[0].size();++j){
23                 C[i][j]=(C[i][j]+(A[i][k]*B[k][j])%mod)%mod;
24             }
25         }
26     }
27     return C;
28 }
29 mat pow(mat A,ll n){
30     mat B (A.size(),vec(A.size()));
31     for(int i=0;i<A.size();++i)B[i][i]=1;
32     while(n>0){
33         if(n&1)B = mul(B,A);
34         A = mul(A,A);
35         n>>=1;
36     }
37     return B;
38 }
39 int n;
40 mat M;
41 void solve(int k){
42     mat A(2*n,vec(2*n));
43     for(int i=0;i<n;++i){
44         for(int j=0;j<n;++j){
45             A[i][j]=M[i][j];
46         }
47         A[i+n][i]=A[i+n][i+n]=1;
48     }
49     A = pow(A,k+1);
50     for(int i=0;i<n;++i){
51         for(int j=0;j<n;++j){
52             int a = A[n+i][j]%mod;
53             if(i==j)a = (a+mod-1)%mod;
54             printf("%d%c",a,j+1==n?'\n':' ');
55         }
56 
57     }
58 }
59 int main (){
60     int k;
61     while(scanf("%d%d%d",&n,&k,&mod)!=EOF){
62         M = mat(n,vec(n));
63         for(int i=0;i<n;++i){
64             for(int j=0;j<n;++j){
65                 scanf("%d",&M[i][j]);
66             }
67         }
68         solve(k);
69     }
70 }
View Code

矩阵快速幂的题目主要还是构造矩阵,如何把题目转化为矩阵这一步才是关键!!!!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!