矩阵乘法
对于矩阵A(m*n)和一个矩阵B(n*p)相乘可以得到一个矩阵C(m*p),定义如下
矩阵乘法满足结合律和分配率,但不满足交换律。
矩阵乘法加速递推
矩阵乘法中一种特殊的情形,F是一个1*n的矩阵,A是一个n*n的矩阵,F'=F*A也是一个1*n的矩阵。F和F'可看作一维数组,省略他们的行下标1。按照矩阵乘法的定义,任意的 j ∈ [1, n] ,有表示的含义是,进过一次与A的矩阵乘法后,F数组中第k个值会以A[k][j]为系数累加到F'数组上第j个值上,等价于在一个向量的k, j两个状态之间发生了递推。
所以我们可以利用矩阵乘法加速递推。
所以对于具有以下特点的题,我们可以利用矩阵加速乘法来加速递推:
- 可以抽象为一个长度为n的一维向量,该项量在每个单位时间内只发生一次变化。
- 变化的形式是线性递推(只有若干“加法”或“乘以一个系数“的运算)。
- 该递推式在每个时间可能作用于不同的数据上,但本身保持不变。
- 向量的变化时间(即递推轮)很长,但向量长度n很小。
我们在这儿做出以下定义
- 状态矩阵:长度为n的一维向量。
- 转移矩阵:用于与状态矩阵相乘的固定不变的矩阵A。
如若状态矩阵的第x个数对下一个单位时间的状态矩阵的第y个矩阵产生影响,我们就把转移矩阵的A[x][y]处赋予适当的系数,然后用矩阵快速幂完成。
矩阵快速幂
1 struct Matrix 2 { 3 int Transition_Matrix[][] ; 4 Matrix friend operator * (Matrix a, Matrix b) 5 { 6 Matrix c; 7 memset(c.Transition_Matrix, 0, sizeof(c.Transition_Matrix)); 8 for(int i = 0; i < 16; ++ i) 9 for(int j = 0; j < 16; ++ j) 10 for(int k = 0; k < 16; ++ k) 11 c.Transition_Matrix[i][j] = (c.Transition_Matrix[i][j] + a.Transition_Matrix[i][k] * b.Transition_Matrix[k][j] % mod) % mod; 12 return c; 13 } 14 Matrix friend operator % (Matrix a, int mod) 15 { 16 for(int i = 1; i < 16; ++ i) 17 for(int j = 1; j < 16; ++ j) 18 a.Transition_Matrix[i][j] = a.Transition_Matrix[i][j] % mod; 19 return a; 20 } 21 Matrix ksm(Matrix a, int b) 22 { 23 Matrix res; 24 memset(res.Transition_Matrix, 0, sizeof(res)); 25 for(int i = 0; i < 16; ++ i) res.Transition_Matrix[i][i] = 1; 26 for(;b; b >>= 1, a = (a * a) % mod) 27 if(b & 1) res = (res * a) % mod; 28 return res; 29 } 30 };