POJ3233]Matrix Power Series

题目:Matrix Power Series

传送门:http://poj.org/problem?id=3233

分析:

方法一:引用Matrix67大佬的矩阵十题:这道题两次二分,相当经典。首先我们知道,A^i可以二分求出。然后我们需要对整个题目的数据规模k进行二分。比如,当k=6时,有:$ S(6)= A + A^2 + A^3 + A^4 + A^5 + A^6 =\underline{(A + A^2 + A^3)} + A^3*\underline{(A + A^2 + A^3)}。   $

即对于k:如果k是偶数,就二分减小规模,$ S(k)=S(\frac{k}{2})+A^{\frac{n}{2}} *S(\frac{k}{2}) $。如果k是奇数,那么 $ S(k)=S(k-1)+A^n $; 其中 $ A^n $使用矩阵快速幂可以快速计算。

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 const int maxN=35;
 5 int MOD;
 6 struct Matrix{int n,a[maxN][maxN];}A,E;
 7 Matrix operator+(Matrix A,Matrix B){
 8     Matrix RT{0};RT.n=A.n;
 9     for(int i=0;i<RT.n;++i)
10     for(int j=0;j<RT.n;++j)
11         RT.a[i][j]=(A.a[i][j]+B.a[i][j])%MOD;
12     return RT;
13 }
14 Matrix operator*(Matrix A,Matrix B){
15     Matrix RT{0};RT.n=A.n;
16     for(int i=0;i<A.n;++i)
17     for(int j=0;j<A.n;++j)
18         for(int k=0;k<A.n;++k)
19             (RT.a[i][j]+=A.a[i][k]*B.a[k][j])%=MOD;
20     return RT;
21 }
22 Matrix operator^(Matrix A,int n){
23     Matrix RT=E;
24     for(;n;n>>=1){
25         if(n&1)RT=RT*A;
26         A=A*A;
27     }
28     return RT;
29 }
30 Matrix Sum(Matrix &A,int n){
31     if(n==1)return A;
32     if(n&1)return (A^n) + Sum(A,n-1);
33     Matrix B=Sum(A,n>>1);
34     return B+((A^(n>>1))*B);
35 }
36 int main(){
37     for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
38         A.n=E.n=n;
39         for(int i=0;i<n;++i)
40         for(int j=0;j<n;++j){
41             scanf("%d",&A.a[i][j]);
42             A.a[i][j]%=MOD;E.a[i][j]=0;
43         }
44         for(int i=0;i<n;++i)E.a[i][i]=1;
45         Matrix RT=Sum(A,k);
46         for(int i=0;i<n;++i){
47             for(int j=0;j<n;++j)
48                 printf("%d ",RT.a[i][j]);
49             puts("");
50         }
51     }
52     return 0;
53 }
View Code

方法二:对于多项式,有秦九韶算法,而对$ A + A^2 + A^3 + … + A^k $ 这样的多项式,可以二进制优化秦九韶算法。$ S( 2^i ) $ 是可以快速计算的: $S( 2^i ) = S( 2^{(i-1)} ) * (E + A^{(2^i)} )$。记:$A[i]=A^{2^i}$、$S[i]=S(2^i)$;预处理A[i]、s[i]。

比如k=6时:$ S(6)=\underline{(A + A^2 + A^3 + A^ 4)} * A^2 + \underline{(A + A^2 )} = S(4) * A(2) + S(2) = S[2]*A[1]+S[1] $

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 const int maxN=35;
 5 int MOD;
 6 struct Matrix{int n,a[maxN][maxN];}A[35],B[35];
 7 Matrix operator+(Matrix A,Matrix B){
 8     Matrix RT{0};RT.n=A.n;
 9     for(int i=0;i<RT.n;++i)
10     for(int j=0;j<RT.n;++j)
11         RT.a[i][j]=(A.a[i][j]+B.a[i][j])%MOD;
12     return RT;
13 }
14 Matrix operator*(Matrix A,Matrix B){
15     Matrix RT{0};RT.n=A.n;
16     for(int i=0;i<A.n;++i)
17     for(int j=0;j<A.n;++j)
18         for(int k=0;k<A.n;++k)
19             (RT.a[i][j]+=A.a[i][k]*B.a[k][j])%=MOD;
20     return RT;
21 }
22 int main(){
23     Matrix E{0};
24     for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
25         A[0].n=E.n=n;
26         for(int i=0;i<n;++i)
27         for(int j=0;j<n;++j){
28             scanf("%d",&A[0].a[i][j]);
29             A[0].a[i][j]%=MOD;E.a[i][j]=0;
30         }
31         for(int i=0;i<n;++i)E.a[i][i]=1;
32         for(int i=1;k>>i;++i)A[i]=A[i-1]*A[i-1];
33         B[0]=A[0];
34         for(int i=1;k>>i;++i)B[i]=B[i-1]*(A[i-1]+E);
35         Matrix RT{0};RT.n=n;
36         for(int i=30;~i;--i)if(k>>i&1)RT=RT*A[i]+B[i];
37         for(int i=0;i<n;++i){
38             for(int j=0;j<n;++j)
39                 printf("%d ",RT.a[i][j]);
40             puts("");
41         }
42     }
43     return 0;
44 }
View Code

优化一下常数(141s -> 32s):

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 const int maxN=35;
 5 int MOD;
 6 struct Matrix{int n,a[maxN][maxN];}A[35],B[35];
 7 Matrix operator+(Matrix A,Matrix B){
 8     Matrix RT{0};RT.n=A.n;
 9     for(int i=0;i<RT.n;++i)
10     for(int j=0;j<RT.n;++j){
11         RT.a[i][j]=A.a[i][j]+B.a[i][j];
12         if(RT.a[i][j]>=MOD)RT.a[i][j]-=MOD;
13     }
14     return RT;
15 }
16 Matrix operator*(Matrix A,Matrix B){
17     Matrix RT{0};RT.n=A.n;
18     for(int i=0;i<A.n;++i)
19     for(int j=0;j<A.n;++j){
20         for(int k=0;k<A.n;++k)
21             RT.a[i][j]+=A.a[i][k]*B.a[k][j];
22         RT.a[i][j]%=MOD;
23     }
24     return RT;
25 }
26 int main(){
27     Matrix E{0};
28     for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
29         A[0].n=E.n=n;
30         for(int i=0;i<n;++i)
31         for(int j=0;j<n;++j){
32             scanf("%d",&A[0].a[i][j]);
33             A[0].a[i][j]%=MOD;E.a[i][j]=0;
34         }
35         for(int i=0;i<n;++i)E.a[i][i]=1;
36         for(int i=1;k>>i;++i)A[i]=A[i-1]*A[i-1];
37         B[0]=A[0];
38         for(int i=1;k>>i;++i)B[i]=B[i-1]*(A[i-1]+E);
39         Matrix RT{0};RT.n=n;
40         for(int i=30;~i;--i)if(k>>i&1)RT=RT*A[i]+B[i];
41         for(int i=0;i<n;++i){
42             for(int j=0;j<n;++j)
43                 printf("%d ",RT.a[i][j]);
44             puts("");
45         }
46     }
47     return 0;
48 }

方法三:有种很有意思的打法:构造矩阵

$ T = \left[ \begin{array}{cc} E & 0 \\ A & A \end{array}  \right]$ 、 $ T^2 =  \left[ \begin{array}{cc} E & 0 \\ {A + A^2}  & A^2 \end{array}  \right]$ 、 $ T^2 =  \left[ \begin{array}{cc} E & 0 \\ {A + A^2 + A^3}  & A^3 \end{array} \right]$ 、

 这个矩阵的左下角就是矩阵次方和。$ T^n =  \left[ \begin{array}{cc} E & 0 \\ {A + A^2 + .. A^n}  & A^n \end{array} \right]$

这个矩阵可以直接快速幂求。

把RT矩阵设为 $ RT =  \left[ \begin{array}{cc} 0 & E \\ 0  & 0 \end{array} \right] $,然后 $ RT \times T^n =   \left[ \begin{array}{cc} {A + A^2 + .. A^n} & 0 \\ 0  & 0 \end{array} \right] $

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 const int maxN=65;
 5 int MOD;
 6 struct Matrix{int n,a[maxN][maxN];}A;
 7 Matrix operator+(Matrix A,Matrix B){
 8     Matrix RT{0};RT.n=A.n;
 9     for(int i=0;i<RT.n;++i)
10     for(int j=0;j<RT.n;++j){
11         RT.a[i][j]=A.a[i][j]+B.a[i][j];
12         if(RT.a[i][j]>=MOD)RT.a[i][j]-=MOD;
13     }
14     return RT;
15 }
16 Matrix operator*(Matrix A,Matrix B){
17     Matrix RT{0};RT.n=A.n;
18     for(int i=0;i<A.n;++i)
19     for(int j=0;j<A.n;++j){
20         for(int k=0;k<A.n;++k)
21             RT.a[i][j]+=A.a[i][k]*B.a[k][j];
22         RT.a[i][j]%=MOD;
23     }
24     return RT;
25 }
26 Matrix Sum(Matrix A,int k){
27     Matrix RT{0};int n=RT.n=A.n;
28     for(int t=n/2,i=0;i<n;++i)RT.a[i][i+t]=1;
29     for(;k;k>>=1){
30         if(k&1)RT=RT*A;
31         A=A*A;
32     }
33     return RT;
34 }
35 int main(){
36     for(int n,k;~scanf("%d %d %d",&n,&k,&MOD);){
37         A.n=n<<1;
38         for(int i=0;i<n;++i){
39             A.a[i][i]=1;
40             for(int j=0,t;j<n;++j){
41                 scanf("%d",&t);if(t>=MOD)t%=MOD;
42                 A.a[i+n][j]=A.a[i+n][j+n]=t;
43             }
44         }
45         Matrix RT=Sum(A,k);
46         for(int i=0;i<n;++i){
47             for(int j=0;j<n;++j)
48                 printf("%d ",RT.a[i][j]);
49             puts("");
50         }
51     }
52     return 0;
53 }

猜你喜欢

转载自www.cnblogs.com/hjj1871984569/p/9978752.html
今日推荐