BZOJ1009 [HNOI2008]GT考试(KMP/AC自动机,矩阵乘法)
文章目录
【注意】最后更新于 July 27, 2020,文中内容可能已过时,请谨慎使用。
题目链接
题意简述
给一个长为 $m$ 的字符串,字符集 $0$ ~ $9$,求长为 $n$ 的字符串中不含给定字符串作为子串的字符串有多少个,对 $k$ 取模。
$n\le10^9$,$m\le20$,$k\le1000$。
简要做法
首先用 KMP / AC 自动机搞出转移:$f_{i,j}$ 表示从状态 $i$ (或者说位置 $i$,KMP 里就是位置,AC 自动机里虽然是节点但也和位置差不多)起,在后面加 $j$ 个字符,满足要求的字符串个数,则 $f_{i,j} = \sum\limits_{x=0}^9f_{tr[i][x],j-1}$,其中 $tr[i][x]$ 表示状态 $i$ 的字符 $x$ 转移。AC 自动机中不用解释了,KMP 里面就是 $tr[i][x]=\begin{cases}i+1&(s[i+1]=x)\\tr[next[i]][x]&(s[i+1]\ne x)\end{cases}$。
发现每层(相同的 $j$)的转移都是类似的,实际上可以用矩阵表示两层间的转移:
$$A\times\begin{bmatrix}f_{0,j}\\f_{1,j}\\\vdots\\f_{m-1,j}\end{bmatrix}=\begin{bmatrix}f_{0,j+1}\\f_{1,j+1}\\\vdots\\f_{m-1,j+1}\end{bmatrix}$$
(只到 $m-1$ 是因为 $f_{m,j}=0$)
其中 $A$ 是我们要求的一个矩阵,$A_{i,j}$ 就是 $\sum\limits_{x=0}^9[tr[i][x]=j]$,求出来之后矩阵快速幂就好了。
参考代码
KMP
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 21;
int n, m, mod, nxt[N];
char s[N];
struct Matrix
{
int a[N][N];
Matrix() { memset(a, 0, sizeof(a)); }
int* operator[](int x) { return a[x]; }
Matrix operator*(Matrix & b)
{
Matrix out;
int i, j, k;
for (i = 0; i < m; ++i)
{
for (j = 0; j < m; ++j)
{
for (k = 0; k < m; ++k)
{
out[i][j] = (out[i][j] + a[i][k] * b[k][j]) % mod;
}
}
}
return out;
}
};
Matrix qpow(Matrix x, int y);
int main()
{
int i, j, k, ans = 0;
Matrix mul;
scanf("%d%d%d%s", &n, &m, &mod, s + 1);
for (i = 2, k = 0; i < m; ++i)
{
while (k && s[i] != s[k + 1]) k = nxt[k];
if (s[i] == s[k + 1]) ++k;
nxt[i] = k;
}
for (i = 0; i < m; ++i)
{
for (j = 0; j <= 9; ++j)
{
for (k = i; k && s[k + 1] - '0' != j; k = nxt[k]);
if (s[k + 1] - '0' == j) ++k;
++mul[i][k];
}
}
mul = qpow(mul, n);
for (i = 0; i < m; ++i) ans = (ans + mul[0][i]) % mod;
cout << ans;
return 0;
}
Matrix qpow(Matrix x, int y)
{
Matrix out;
for (int i = 0; i < m; ++i) out[i][i] = 1;
while (y)
{
if (y & 1) out = out * x;
x = x * x;
y >>= 1;
}
return out;
}
AC 自动机
如果觉得我的 AC 自动机写法比较清奇可以看看我的 AC 自动机学习笔记..
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 21;
int n, m, mod, tr[N][10], fail[N];
char s[N];
struct Matrix
{
int a[N][N];
Matrix() { memset(a, 0, sizeof(a)); }
int* operator[](int x) { return a[x]; }
Matrix operator*(Matrix & b)
{
Matrix out;
int i, j, k;
for (i = 0; i < m; ++i)
{
for (j = 0; j < m; ++j)
{
for (k = 0; k < m; ++k)
{
out[i][j] = (out[i][j] + a[i][k] * b[k][j]) % mod;
}
}
}
return out;
}
};
Matrix qpow(Matrix x, int y);
int main()
{
int i, j, ans = 0;
Matrix mul;
scanf("%d%d%d%s", &n, &m, &mod, s + 2);
for (i = 0; i <= 9; ++i) tr[0][i] = 1;
for (i = 1; i <= m; ++i)
{
tr[i][s[i + 1] - '0'] = i + 1;
for (j = 0; j <= 9; ++j)
{
if (s[i + 1] - '0' == j) fail[i + 1] = tr[fail[i]][j];
else tr[i][j] = tr[fail[i]][j];
++mul[i - 1][tr[i][j] - 1];
}
}
mul = qpow(mul, n);
for (i = 0; i < m; ++i) ans = (ans + mul[0][i]) % mod;
cout << ans;
return 0;
}
Matrix qpow(Matrix x, int y)
{
Matrix out;
for (int i = 0; i < m; ++i) out[i][i] = 1;
while (y)
{
if (y & 1) out = out * x;
x = x * x;
y >>= 1;
}
return out;
}
评论正在加载中...如果评论较长时间无法加载,你可以 搜索对应的 issue 或者 新建一个 issue 。