POJ 3233 Matrix Power Series (矩阵 && 求和 && 线性变换)

题目大意:给定n阶方阵A,计算S = A^1+A^2+……+A^k  (mod m)  (k <= 10^9)   我们可以根据矩阵快速幂在O(n^3log(k))的时间里算出A^k,但我们也不能一个一个算再加起来啊,那样铁定超时……   ①二分 这种方法我觉得与 秦九韶算法计算多项式的思路类似,都是找出重复因子而减少多项式计算的次数.当然我们这个多项式比较特殊,所以有比秦九韶算法更好的思路: 当k为偶数时: S(k) = A^1+A^2+A^3 + A^(k/2) + A^(k/2+1) + …… + A^(k/2+k/2) = (A^(k/2) + E) (A^1 + A^2 + A^3 …… + A^(k/2) ) =(A^(k/2) + E) * S(k/2) 当k为奇数时: S(k) = S(k-1) * A^k   这种方法可能出现递归过深的问题,所以要设置好占空间小心栈溢出,而且速度也偏慢
11217405 AbandonZHANG 3233 Accepted 3532K 704MS G++ 2444B 2013-01-28 20:53:36
 
#include 
 
   
    
  
#include 
  
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
         
           #include 
          
            #include 
            #include 
            
              #include 
             
               #include 
              
                #define MID(x,y) ((x+y)>>1) #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; const int MAX = 30; struct Mat{ int row, col; LL mat[MAX][MAX]; }; //initialize square matrix to unit matrix Mat unit(int n){ Mat A; A.row = A.col = n; memset(A.mat, 0, sizeof(A.mat)); for (int i = 0; i < n; i ++) A.mat[i][i] = 1; return A; } //return T(A) Mat transpose(Mat A){ Mat T; T.row = A.col; T.col = A.row; for (int i = 0; i < A.col; i ++) for (int j = 0; j < A.row; j ++) T.mat[i][j] = A.mat[j][i]; return T; } //return (A+B)%mod Mat add(Mat A, Mat B, int mod){ Mat C = A; for (int i = 0; i < C.row; i ++) for (int j = 0; j < C.col; j ++) C.mat[i][j] = (A.mat[i][j] + B.mat[i][j]) % mod; return C; } //return A*B%mod Mat mul(Mat A, Mat B, int mod){ Mat C; C.row = A.row; C.col = B.col; for (int i = 0; i < A.row; i ++){ for (int j = 0; j < B.col; j ++){ C.mat[i][j] = 0; for (int k = 0; k < A.col; k ++) //注意这里要保证乘法不溢出,否则还需要设计特殊的乘法模 C.mat[i][j] += A.mat[i][k] * B.mat[k][j]; C.mat[i][j] %= mod; } } return C; }; //return A^n%mod Mat exp_mod(Mat A, int n, int mod){ Mat res = unit(A.row); while(n){ if (n & 1){ res = mul(res, A, mod); } A = mul(A, A, mod); n >>= 1; } return res; } Mat A; int n, k, mod; Mat S(int k){ if (k == 1){ return A; } if (k % 2 == 0){ return mul(add(exp_mod(A, k/2, mod), unit(n), mod), S(k/2), mod); } else{ return add(S(k-1), exp_mod(A, k, mod), mod); } } int main(){ cin >> n >> k >> mod; A.row = A.col = n; for (int i = 0; i < n; i ++) for (int j = 0; j < n; j ++) cin >> A.mat[i][j]; Mat ans = S(k); for (int i = 0; i < ans.row; i ++){ for (int j = 0; j < ans.col - 1; j ++) cout << ans.mat[i][j] << " "; cout << ans.mat[i][ans.col-1] << endl; } return 0; } 
               
              
             
           
          
         
        
       
      
    
 
   
  ②线性变换(很赞的一种方法呐~!涨姿势~) 我们考虑递推,即从s(k-1)到s(k)的线性变换。 首先一维线性变换显然是出不来的,就像A^1+A^2+A^3+……+A^k = d * (A^1+A^2+A^3+……+A^(k-1)  ) 明显不行…… 那么我们再加一维就显然了: A^1+A^2+A^3+……+A^k =( A^1+A^2+A^3+……+A^(k-1)  ) + A^k A^(k+1) = 0 * ( A^1+A^2+A^3+……+A^(k-1)  ) + A * A^k.        //这一行的变换是作为辅助,补全二维的线性变换. 那么线性变换矩阵B显然就是: 1 1 0 1 一般化就有 s(k)                    1  1             s(k-1) A^k+1     =     0  1     *     A^k 即P(k) = B^(n-1) * P(1)   这样要比①好多了,又省空间又省时间。
11217490 AbandonZHANG 3233 Accepted 1016K 282MS G++ 2962B 2013-01-28 21:25:37
 
#include 
 
   
    
  
#include 
  
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
         
           #include 
          
            #include 
            #include 
            
              #include 
             
               #include 
              
                #define MID(x,y) ((x+y)>>1) #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; const int MAX = 60; struct Mat{ int row, col; LL mat[MAX][MAX]; }; //initialize square matrix to unit matrix Mat unit(int n){ Mat A; A.row = A.col = n; memset(A.mat, 0, sizeof(A.mat)); for (int i = 0; i < n; i ++) A.mat[i][i] = 1; return A; } //return T(A) Mat transpose(Mat A){ Mat T; T.row = A.col; T.col = A.row; for (int i = 0; i < A.col; i ++) for (int j = 0; j < A.row; j ++) T.mat[i][j] = A.mat[j][i]; return T; } //return (A+B)%mod Mat add(Mat A, Mat B, int mod){ Mat C = A; for (int i = 0; i < C.row; i ++) for (int j = 0; j < C.col; j ++) C.mat[i][j] = (A.mat[i][j] + B.mat[i][j]) % mod; return C; } //return A*B%mod Mat mul(Mat A, Mat B, int mod){ Mat C; C.row = A.row; C.col = B.col; for (int i = 0; i < A.row; i ++){ for (int j = 0; j < B.col; j ++){ C.mat[i][j] = 0; for (int k = 0; k < A.col; k ++) //注意这里要保证乘法不溢出,否则还需要设计特殊的乘法模 C.mat[i][j] += A.mat[i][k] * B.mat[k][j]; C.mat[i][j] %= mod; } } return C; }; //return A^n%mod Mat exp_mod(Mat A, int n, int mod){ Mat res = unit(A.row); while(n){ if (n & 1){ res = mul(res, A, mod); } A = mul(A, A, mod); n >>= 1; } return res; } Mat A; int n, k, mod; int main(){ cin >> n >> k >> mod; A.row = A.col = n; for (int i = 0; i < n; i ++) for (int j = 0; j < n; j ++) cin >> A.mat[i][j]; Mat res; res.row = 2 * n; res.col = n; for (int i = 0; i < n; i ++) for (int j = 0; j < n; j ++) res.mat[i][j] = A.mat[i][j]; for (int i = n; i < 2 * n; i ++) for (int j = 0; j < n; j ++) res.mat[i][j] = A.mat[i-n][j]; Mat E = unit(n); Mat B; memset(B.mat, 0, sizeof(B.mat)); B.row = B.col = 2 * n; for (int i = 0; i < n; i ++){ for (int j = 0; j < n; j ++) B.mat[i][j] = E.mat[i][j]; for (int j = n; j < 2 * n; j ++) B.mat[i][j] = A.mat[i][j-n]; } for (int i = n; i < 2 * n; i ++){ for (int j = n; j < 2 * n; j ++) B.mat[i][j] = A.mat[i-n][j-n]; } B = exp_mod(B, k-1, mod); res = mul(B, res, mod); for (int i = 0; i < n; i ++){ for (int j = 0; j < n - 1; j ++) cout << res.mat[i][j] << " "; cout << res.mat[i][n-1] << endl; } return 0; } 
               
              
             
           
          
         
        
       
      
    
 
   
 

你可能感兴趣的:(Matrix)