1. 程式人生 > >POJ3233]Matrix Power Series

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 }