$$AVICII$$

矩阵乘法优化dp

题表

P3390 【模板】矩阵快速幂

板子

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=110;
 4 const int mod=1e9+7;
 5 int n;
 6 struct Matrix{
 7     int jz[MAXN][MAXN];
 8     inline void init(){
 9         for(int i=1;i<=n;++i)
10             for(int j=1;j<=n;++j)
11                 jz[i][j]=0;
12         return ;
13     }
14     friend Matrix operator *(Matrix a,Matrix b){
15         Matrix tmp;tmp.init();
16         for(int k=1;k<=n;++k)
17             for(int i=1;i<=n;++i)
18                 for(int j=1;j<=n;++j)
19                     tmp.jz[i][j]=(tmp.jz[i][j]+1LL*a.jz[i][k]*b.jz[k][j]%mod)%mod;
20         return tmp;
21     }
22 };
23 Matrix ans,a;
24 long long K;
25 int main(){
26     //freopen("P3390_1.in","r",stdin);
27     scanf("%d%lld",&n,&K);
28     ans.init();a.init();
29     for(int i=1;i<=n;++i)ans.jz[i][i]=1;
30     for(int i=1;i<=n;++i)
31         for(int j=1;j<=n;++j)
32             scanf("%d",&a.jz[i][j]);
33     for(;K;K>>=1,a=a*a)
34         if(K&1)ans=ans*a;
35     for(int i=1;i<=n;++i,puts(""))
36         for(int j=1;j<=n;++j)
37             printf("%d ",ans.jz[i][j]);
38     return 0;
39 } 
View Code

P1962 斐波那契数列

最简单的优化dp问题,但是不要拘泥于这种优化dp的矩阵书写格式,理解透彻给dp乘系数的算法

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=1e9+7;
 4 int F[3];
 5 struct Matrix{
 6     int jz[3][3];
 7     inline void init(){
 8         for(int i=1;i<=2;++i)
 9             for(int j=1;j<=2;++j)
10                 jz[i][j]=0;
11         return ;
12     }
13     friend Matrix operator *(const Matrix a,const Matrix b){
14         Matrix tmp;tmp.init();
15         for(int k=1;k<=2;++k)
16             for(int i=1;i<=2;++i)
17                 for(int j=1;j<=2;++j)
18                     tmp.jz[i][j]=(tmp.jz[i][j]+1LL*a.jz[i][k]*b.jz[k][j]%mod)%mod;
19         return tmp;
20     }
21 };
22 Matrix a,ans;
23 long long n;
24 int main(){
25     //freopen("P1939_3.in","r",stdin);
26     scanf("%lld",&n);
27     if(n<=2)printf("%d\n",1);
28     else{
29         F[1]=F[2]=1;
30         a.jz[1][1]=0;a.jz[1][2]=1;
31         a.jz[2][1]=1;a.jz[2][2]=1;
32         ans.init();
33         for(int i=1;i<=2;++i)ans.jz[i][i]=1;
34         n-=2;
35         for(;n;n>>=1,a=a*a)
36             if(n&1)ans=ans*a;
37         printf("%d\n",(1LL*F[1]*ans.jz[1][2]%mod+1LL*F[2]*ans.jz[2][2]%mod)%mod);
38     }
39     return 0;
40 } 
View Code

P1397 [NOI2013] 矩阵游戏

做题时拘泥于上题的构造矩阵格式,写了一个大小为3*3的矩阵

看题解又写了一个2*2的矩阵$$\left[\begin{matrix} a & 0 \\ 1 & 1 \end{matrix} \right]$$

和答案矩阵$$\left[\begin{matrix} ans & b \\ 0 & 0 \end{matrix} \right]$$ 

然后发现这样行和列答案矩阵不统一,应该把第一个矩阵的1和答案矩阵的b互换

即答案矩阵$ANS$为$$\left[\begin{matrix} ans & 1 \\ 0 & 0 \end{matrix} \right]$$ 

行转移A为$$\left[\begin{matrix} c & 0 \\ d & 1 \end{matrix} \right]$$ 

列转移B为$$\left[\begin{matrix} a & 0 \\ b & 1 \end{matrix} \right]$$ 

答案即为$ANS*B^{m-1}*{(B^{m-1}*A)}^{n-1}$

注意矩阵乘不满足交换律,满足结合律,所以顺序不能所以调换

 1 //灵活运用矩阵优化
 2 //十进制快速幂 
 3 #include<bits/stdc++.h>
 4 using namespace std;
 5 const int MAXN=1e6+17;
 6 const int mod=1e9+7;
 7 char n[MAXN],m[MAXN];
 8 int a,b,c,d;
 9 struct Matrix{
10     int jz[2][2];
11     void init(){
12         jz[0][0]=jz[0][1]=jz[1][0]=jz[1][1]=0;
13         return ;
14     }
15     void pt(){
16         cout<<"PRT"<<endl;
17         cout<<jz[0][0]<<" "<<jz[0][1]<<endl;
18         cout<<jz[1][0]<<" "<<jz[1][1]<<endl;
19         return ;
20     }
21     friend Matrix operator *(const Matrix x,const Matrix y){
22         Matrix tmp;tmp.init();
23         tmp.jz[0][0]=(1LL*x.jz[0][0]*y.jz[0][0]%mod+1LL*x.jz[0][1]*y.jz[1][0]%mod)%mod;
24         tmp.jz[0][1]=(1LL*x.jz[0][0]*y.jz[0][1]%mod+1LL*x.jz[0][1]*y.jz[1][1]%mod)%mod;
25         tmp.jz[1][0]=(1LL*x.jz[1][0]*y.jz[0][0]%mod+1LL*x.jz[1][1]*y.jz[1][0]%mod)%mod;
26         tmp.jz[1][1]=(1LL*x.jz[1][0]*y.jz[0][1]%mod+1LL*x.jz[1][1]*y.jz[1][1]%mod)%mod;
27         return tmp;
28     }
29 }ans,base,tmp;
30 int len,jie;
31 int main(){
32     scanf("%s%s%d%d%d%d",n+1,m+1,&a,&b,&c,&d);
33     len=strlen(n+1);jie=1;
34     for(int i=len;i>=1;--i){
35         int idx=n[i]-'0';
36         if(jie<=idx){n[i]=idx-jie+'0';break; }
37         n[i]=idx+10-jie+'0',jie=1;
38     }
39     len=strlen(m+1);jie=1;
40     for(int i=len;i>=1;--i){
41         int idx=m[i]-'0';
42         if(jie<=idx){m[i]=idx-jie+'0';break; }
43         m[i]=idx+10-jie+'0',jie=1;
44     }
45     ans.init();base.init();
46     ans.jz[0][0]=ans.jz[1][1]=1;
47     base.jz[0][0]=a;base.jz[0][1]=0;
48     base.jz[1][0]=b;base.jz[1][1]=1;
49     len=strlen(m+1);
50     for(int i=len;i>=1;--i){
51         int idx=m[i]-'0';
52         while(idx--){
53             ans=ans*base;
54             //ans.pt();
55         }
56         base=base*base*base*base*base*base*base*base*base*base;
57     }
58     base.jz[0][0]=c;base.jz[0][1]=0;
59     base.jz[1][0]=d;base.jz[1][1]=1;
60     tmp=ans;base=base*ans;
61     ans.init();ans.jz[0][0]=ans.jz[0][1]=1;
62     ans=ans*tmp;
63     len=strlen(n+1);
64     for(int i=len;i>=1;--i){
65         int idx=n[i]-'0';
66         while(idx--){
67             ans=ans*base;
68             //ans.pt();
69         }
70         base=base*base*base*base*base*base*base*base*base*base;
71     }
72     printf("%d\n",ans.jz[0][0]);
73     return 0;
74 } 
View Code

P2461 [SDOI2008] 递归数列

维护k+1*k+1的矩阵,多出来的一个维护答案,因为答案是合,矩阵k位的每次更新乘对应系数,矩阵中小于k的位置直接把平移

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 int k,p;
 5 int b[110],c[110];
 6 LL n,m;
 7 struct Matrix{
 8     int jz[21][21];
 9     inline void init(){
10         for(int i=1;i<=k+1;++i)
11             for(int j=1;j<=k+1;++j)
12                 jz[i][j]=0;
13         return ;
14     }
15     inline void pt(){
16         cout<<"EEEE "<<endl;
17         for(int i=1;i<=k+1;++i,puts(""))
18             for(int j=1;j<=k+1;++j)
19                 printf("%d ",jz[i][j]);
20         return ;
21     }
22     friend Matrix operator *(const Matrix a,const Matrix b){
23         Matrix tmp;tmp.init();
24         for(int o=1;o<=k+1;++o)
25             for(int i=1;i<=k+1;++i)
26                 for(int j=1;j<=k+1;++j)
27                     tmp.jz[i][j]=(tmp.jz[i][j]+1LL*a.jz[i][o]*b.jz[o][j]%p)%p;
28         return tmp;
29     }
30 }F,a;
31 int Get(LL x){
32     if(x<=(LL)k){
33         int ans=0;
34         for(int i=1;i<=x;++i)ans=(ans+b[i])%p;
35         return ans;
36     }
37     F.init();a.init();
38     for(int i=1;i<k;++i)F.jz[1][i]=b[i],F.jz[1][k+1]=(F.jz[1][k+1]+b[i])%p;
39     F.jz[1][k]=b[k];
40     //F.pt();
41     a.jz[k+1][k+1]=1;a.jz[k][k+1]=1;
42     for(int i=1;i<k;++i)a.jz[i+1][i]=1;
43     for(int j=1;j<=k;++j)a.jz[j][k]=c[k-j+1];
44     //a.pt();
45     x-=k-1;
46     for(;x;x>>=1,a=a*a)
47         if(x&1)F=F*a;
48     //for(int i=1;i<=x;++i)F=F*a,F.pt();
49     return F.jz[1][k+1];
50 }
51 int main(){
52     scanf("%d",&k);
53     for(int i=1;i<=k;++i)scanf("%d",&b[i]);
54     for(int i=1;i<=k;++i)scanf("%d",&c[i]);
55     scanf("%lld%lld%d",&m,&n,&p);
56     //cout<<m-1<<" "<<Get(m-1)<<endl;
57     //cout<<n<<" "<<Get(n)<<endl;
58     printf("%d\n",(Get(n)-Get(m-1)+p)%p);
59     return 0;
60 } 
61 /*
62 
63 2
64 1 1
65 1 1
66 2 10 1000003
67 
68 */
View Code

 

 

 

posted @ 2021-11-09 21:05  bootpuss  阅读(77)  评论(0编辑  收藏  举报