矩阵相乘和快速幂基本模板
1 typedef vector<int> vec; 2 typedef vector<vec> mat; 3 4 //计算A*B 5 mat mul(mat &A, mat &B) { 6 mat C(A.size(), vec(B[0].size())); 7 for (int i = 0; i < A.size(); i++) { 8 for (int k = 0; k < B.size(); k++) { 9 for (int j = 0; j < B[0].size(); j++) { 10 C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD; 11 } 12 } 13 } 14 return C; 15 } 16 17 //计算A^n 18 mat mat_pow(mat A, LL n) { 19 mat B(A.size(), vec(A.size())); 20 for (int i = 0; i < A.size(); i++) { 21 B[i][i] = 1; 22 } 23 while (n > 0) { 24 if (n & 1) B = mul(B, A); 25 A = mul(A, A); 26 n >>= 1; 27 } 28 return B; 29 }
POJ 3734 Blocks
题意:
N个方块排成一列,使用红蓝黄绿四种颜色给方块涂色,求染成后的红色方块和染成的绿色的方块的个数同时是偶数的方案总数,输出对10007取模后的答案
解法:
试着从左边开始一次染色,染到第i个方块为止,红绿都是偶数的方案数为$a_i$,红绿恰有一个是偶数的方案为$b_i$,红绿都有的方案为$c_i$, 这样,染到第i+1个方块的时候,红绿都是偶数的方案数有以下两种可能:
1. 红绿都是偶数,且第i+1个为蓝色或黄色
2. 红绿恰有一个为奇数,且第i+1个染成了奇数个对应的那种颜色
那么有如下递推式:
$a_{i+1}=2a_i+b_i$
$b_{i+1}=2a_i+2b_i+2c_i$
$c_{i+1}=b_i+2c_i$
有一下矩阵式子:
Ai+1 2 1 0 Ai
Bi+1 = 2 2 2 Bi
Ci+1 0 1 2 Ci
等效于等号右边部分,左边的矩阵i次方,右边的为$a_0$,$b_0$, $c_0$
快速幂求解。
代码如下:
1 typedef vector<int> vec; 2 typedef vector<vec> mat; 3 4 //计算A*B 5 mat mul(mat &A, mat &B) { 6 mat C(A.size(), vec(B[0].size())); 7 for (int i = 0; i < A.size(); i++) { 8 for (int k = 0; k < B.size(); k++) { 9 for (int j = 0; j < B[0].size(); j++) { 10 C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD; 11 } 12 } 13 } 14 return C; 15 } 16 17 //计算A^n 18 mat mat_pow(mat A, int n) { 19 mat B(A.size(), vec(A.size())); 20 for (int i = 0; i < A.size(); i++) { 21 B[i][i] = 1; 22 } 23 while (n > 0) { 24 if (n & 1) B = mul(B, A); 25 A = mul(A, A); 26 n >>= 1; 27 } 28 return B; 29 } 30 31 int N; 32 33 void solve() { 34 mat A(3, vec(3)); 35 A[0][0] = 2; 36 A[0][1] = 1; 37 A[0][2] = 0; 38 A[1][0] = 2; 39 A[1][1] = 2; 40 A[1][2] = 2; 41 A[2][0] = 0; 42 A[2][1] = 1; 43 A[2][2] = 2; 44 // A = mat_pow(A, N); 45 printf("%d ", A[0][0]); 46 } 47 48 int main() { 49 scanf("%d", &N); 50 solve(); 51 return 0; 52 }