AC 自动机

失配指针

定义 fail 为广义的 $\pi$ 函数即对于 $n$ 个字符串$fail_{i,j}=\max\limits_{k=1}^n \pi(S_k\#S_{i,1\sim j})$

上面那个是一种定义但事实上$\rm AC$ 自动机中fail 是具有指向性的它指向的是所有模式串中前缀与当前字符串某个前缀的后缀匹配可以产生最大匹配的那个串它与当前串匹配的最后一个结点

构建 AC 自动机

首先对所有模式串建立 Trie 树显然 Trie 树上的每一个结点都对应某个模式串的某个前缀

然后将每个 fail 都指向匹配的结点显而易见所有的 fail 都指向一个祖先节点这个性质后面要用到

最后构建转移边 AutoAuto 指向跳 fail 过程中存在字符 $c$ 的结点

具体来说可以以 $\rm BFS$ 序遍历 Trie 树在遍历的同时更新答案转移式如下

$$\begin{cases}fail_u=Auto_{fail_{fa_u},c}\\Auto_{u,c}=Auto_{fail_u,c}\end{cases} $$

$\rm AC$ 自动机复杂度为 $\Theta(|\Sigma|n)$

文本串匹配

遍历文本串直接按照转移边走即可如果要统计每个模式串出现的次数就将所有经过的点权值 $+1$再在 fail 树上差分即可计算

令模式串为 $S$文本串为 $T$总时间复杂度为 $\Theta(|\Sigma||S|+|T|)$

例题[HNOI2004]L语言

首先有一个显然的 $\Theta(|s|\sum|t|)$ 暴力枚举文本串的转移点显然其不能超过最大串长转移式为

$$f_i=\bigvee_{j=i-|s|}^{i-1}\{f_j\wedge[t_{j+1\sim i}\in s]\} $$

这个式子的核心在于$f_i=true$ 当且仅当它存在一个后缀这个后缀是某个模式串并且删去这个后缀以后的文本串仍合法

于是考虑建立 $\rm AC$ 自动机将文本串放在自动机上跑的时候记 $f_i$ 表示当前前缀是否合法

存在如下 $\rm AC$ 自动机性质如果 $v$ 可以从 $u$ 开始由跳 fail 得到即 fail 树上 $v$$u$ 的祖先那么 $v$ 代表的字符串是 $u$ 代表的字符串的一个后缀

所以从 $u$ 开始遍历跳 fail 经过的结点如果它代表的字符串长度为 $l$且为某个模式串的结尾则将 $g_{u,l}$ 记为 true 由于 $|s|\leqslant 10$所以只有当 $l\leqslant 10$ 的时候 $g_{u,l}$ 可能为 true故直接状压成 $g_u$其二进制下第 $l$ 位表示之前 $g_{u,l}$ 的值

最后直接将文本串放在 $\rm AC$ 自动机上跑即可$now_i$ 表示文本串中当前点前 $i$ 位的 $f$ 值为多少易知 $i\leqslant 10$故也可以状压成一个数 $now$ 易知 $f_i=true$ 当且仅当 $[now~or~g_u]=true$

总时间复杂度 $\Theta(|\Sigma|n|s|^2+m|t|)$