[bzoj 1009] [HNOI2008]GT考试:DP,单串AC自动机,矩阵快速幂
来源:互联网 发布:em算法硬币 编辑:程序博客网 时间:2024/05/23 12:40
题意:给一个长为M(M<=20)的十进制数字串,求有多少个长为N(N<=10^9)的十进制数字串不包含它,结果对K(K<=10^3)取模。
在黄学长博客的KMP分类中找到这题。并没产生什么好思路……准确地说是没深入思考,应该批评。如果把f[i][S]
——前i个字符,以S为(M-1)后缀——作为状态,那么来个20维的DP是能想到的……枚举第(i+1)个字符,只要不形成给定的模板串就可以转移。
把这个暴力放到AC自动机上。这里只有一串。f[i][j]
表示文本串的前i个字符匹配到Trie图前j个结点的方案数。如果有一条边(j, k),那么f[i+1][k] += f[i][j]
。矩阵快速幂优化。
另一种理解方式。每一个合法文本串对应Trie图上从起点开始的一条路径。求出Trie图的邻接矩阵。对邻接矩阵做矩阵乘法,即得任意两点间恰好经过N条边的路径数。
解法来源于[bzoj 1030] [JSOI2007]文本生成器。
用矩阵乘法优化DP的关键在于构造转移矩阵A。如果想让转移矩阵乘到右边,那么A[i][j]
是i对j的贡献。如果想让转移矩阵乘到左边,那么A[i][j]
是i从j得到的贡献。
我的矩阵快速幂写的不是很优雅……几个数组复制来复制去的……黄学长用迭代写的,很精简。
一开始我真的是用KMP的失配指针转移的……没仔细想。失配不一定只跳一次嘛,这样怎么能让长度为N的字符串和经过N条边的路径对应呢?其实AC自动机也有多种写法,这里要用补完版本。
放两份代码。第二份是纯暴力,可以用于检验小数据。
#include <cstdio>#include <cstring>using namespace std;int N, M, K;const int MAX_M = 20, sz = sizeof(int)*MAX_M*MAX_M, SS = 10;char a[MAX_M+1];int A[MAX_M][MAX_M], next[MAX_M][10], fail[MAX_M];void build(){ A[0][0] = SS-1; if (M == 1) return; A[0][1] = 1; next[0][a[0]] = 1; for (int i = 1; i < M; ++i) { if (i > 1) fail[i] = next[fail[i-1]][a[i-1]]; for (int j = 0; j < SS; ++j) { if (i == M-1 && j == a[i]) continue; next[i][j] = j == a[i] ? i+1 : next[fail[i]][j]; if (++A[i][next[i][j]] == K) A[i][next[i][j]] = 0; } }}void matrix_mul(int C[MAX_M][MAX_M], int A[MAX_M][MAX_M], int B[MAX_M][MAX_M]){ memset(C, 0, sz); for (int i = 0; i < M; ++i) for (int j = 0; j < M; ++j) for (int k = 0; k < M; ++k) (C[i][j] += A[i][k] * B[k][j]) %= K; }void matrix_exp(int A[MAX_M][MAX_M], int n){ if (n == 0) { memset(A, 0, sz); for (int i = 0; i < M; ++i) A[i][i] = 1; return; } if (n == 1) return; int B[MAX_M][MAX_M], C[MAX_M][MAX_M]; memcpy(B, A, sz); // B = A matrix_exp(A, n/2); matrix_mul(C, A, A); if (n & 1) matrix_mul(A, C, B); else memcpy(A, C, sz); // A = C}int main(){ scanf("%d %d %d %s", &N, &M, &K, a); for (int i = 0; i < M; ++i) a[i] -= '0'; build(); matrix_exp(A, N); int ans = 0; for (int j = 0; j < M; ++j) ans = (ans + A[0][j]) % K; printf("%d\n", ans); return 0;}
#include <cstdio>#include <cstring>using namespace std;const int MAX_N = 10, MAX_M = 10, SS = 10;int N, M, K;char a[MAX_M], b[MAX_N];int search(int k){ int ans = 0; if (k == N) { bool ok = false; for (int i = 0; i < N; ++i) if (i+M <= N && !strncmp(a, b+i, M)) { ok = true; break; } return !ok; } for (int i = 0; i < SS; ++i) { b[k] = i+'0'; (ans += search(k+1)) %= K; } return ans;}int main(){ scanf("%d %d %d %s", &N, &M, &K, a); printf("%d\n", search(0)); return 0;}
0 0
- [bzoj 1009] [HNOI2008]GT考试:DP,单串AC自动机,矩阵快速幂
- BZOJ 1009: [HNOI2008]GT考试 AC自动机+矩阵快速幂
- [BZOJ]1009 [HNOI2008]GT考试(ac自动机+矩阵快速幂优化状态转移)
- BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法
- bzoj 1009: [HNOI2008]GT考试(AC自动机+矩阵优化dp)
- [BZOJ1009][HNOI2008]GT考试(AC自动机+dp+矩阵优化)
- bzoj1009 GT考试(AC自动机+DP+矩阵快速幂)
- BZOJ KMP+矩阵快速幂 1009: [HNOI2008]GT考试
- [KMP DP 矩阵快速幂加速] BZOJ 1009 [HNOI2008]GT考试
- BZOJ 1009: [HNOI2008]GT考试【KMP上DP+矩阵快速幂
- bzoj 1009: [HNOI2008]GT考试(dp+kmp+矩阵快速幂)
- BZOJ 1009: [HNOI2008]GT考试(DP+KMP失配+矩阵快速幂)
- BZOJ 1009([HNOI2008]GT考试-KMP+矩阵加速Dp)
- 【BZOJ】1009 [HNOI2008]GT考试 KMP+DP+矩阵优化
- 【BZOJ1009】【HNOI2008】GT考试 AC自动机+矩阵乘法
- BZOJ 1009 GT考试 KMP+DP+矩阵快速幂
- BZOJ 1009 GT考试 DP+矩阵快速幂
- BZOJ 1009-GT考试(kmp+矩阵快速幂+DP)
- 如何导出caffemodel参数
- JavaScript实现Ajax请求简单示例
- CodeForces733D Kostya the Sculptor 贪心+二分
- HihoCode 1284 : 机会渺茫【约数个数】
- void (*signal(int sig, void (*func) (int))) (int)理解
- [bzoj 1009] [HNOI2008]GT考试:DP,单串AC自动机,矩阵快速幂
- java的反射机制
- python Json
- 身份证号码验证
- Ubuntu 14.04 编译安装 Tengine + PHP5.6
- 第九周OJ——等比数列
- 跨站脚本之攻防
- HTML5 canvas 绘制的文字如何换行?
- Hadoop元数据解析