BZOJ1009: [HNOI2008]GT考试 (矩阵快速幂 + DP)
题意:求一个长度为n的数字字符串 (n <= 1e9)
不出现子串s的方案数
题解:用f i,j表示长度为i匹配到在子串j的答案
用kmp的失配函数预处理一下 然后这个转移每一个都是一样的 所以可以用矩阵加速
#include <bits/stdc++.h> using namespace std; int n, m, mod; char s[25]; int fail[25]; struct node { int c[25][25]; }a, re; node mul(node x, node y) { node res; memset(res.c, 0, sizeof(res.c)); for(int i = 0; i < m; i++) for(int j = 0; j < m; j++) for(int k = 0; k < m; k++) res.c[i][j] = (res.c[i][j] + x.c[i][k] * y.c[k][j] % mod) % mod; return res; } node pow_mod(node x, int y) { node res; memset(res.c, 0, sizeof(res.c)); for(int i = 0; i < m; i++) res.c[i][i] = 1; while(y) { if(y & 1) res = mul(res, x); x = mul(x, x); y >>= 1; } return res; } int main() { scanf("%d%d%d", &n, &m, &mod); scanf("%s", s + 1); fail[1] = fail[2] = 0; for(int i = 2; i <= m; i++) { int j = fail[i - 1]; while(j && s[i] != s[j + 1]) j = fail[j]; fail[i] = s[i] == s[j + 1] ? j + 1 : 0; } for(int i = 0; i < m; i++) { for(int j = 0; j < 10; j++) { int k = i; while(k && (s[k + 1] - '0') != j) k = fail[k]; if(s[k + 1] - '0' == j) k++; if(k != m) a.c[i][k] = (a.c[i][k] + 1) % mod; } } re = pow_mod(a, n); int ans = 0; for(int i = 0; i < m; i++) ans = (ans + re.c[0][i]) % mod; printf("%d\n", ans); return 0; }