学习心得 - 字符串 - ACAM

前言

所谓 AC 自动机就是 KMP+Trie,不算很难。

问题

\(n\) 个模式串,\(1\) 个文本串,求多少个模式串在文本串中出现过。

我们发现,\(n=1\) 时这玩意就是个 KMP。

然后,我们可以对模式串建 Trie。

例子

例如,\(s=[\tt i, he, his, she, hers]\)。

我们简单建一下普通的 Trie。

这时,我们有文本串 \(\tt shersheishis\)。

我们发现,第 \(1\) 次匹配成功 \(\tt she\),但是下一个 \(\tt r\) 失配了,我们这时要从头来么?

显然不优,可以试图采用 KMP 的思想,类似 \(next\) 指针,跳跃。

这时我们就要引入 \(fail\) 指针了。

\(fail\) 指针

含义:在点 \(i\) 失配后,调到 \(fail_i\) 指向的 \(j\),实现 KMP 的跳跃功能。

我们首先画出 \(fail\) 指针,才能更好理解。

首先,我们将 \(root\) 的 \(fail_i\) 和其的子节点的 \(fail_i\) 设为 \(root(0)\)。

然后,我们要求一个点的 \(fail_i\),设其为 \(p\),先要走到这个点的父亲。

然后直接跳 \(fail_{fa_i}\)。

要是有一个子节点 \(q\),字符 \(=ch_p\),那么 \(fail_p=q\)。

要是一直失配,那么连到 \(root(0)\)。

即,后退,跳跃,标记。

我们发现,这是一个递归的过程。

实现中我们常用 BFS 完成 getf()。

这样就可以非常好理解的完成求解 \(fail\) 指针,效果与 \(next\) 几乎一样。

代码

咕咕咕。

查询

参造 Trie 的查询方法,搞一个 \(p\) 来跳,要是失配就跳 fail,应该就可以了。

代码

咕咕咕。

拓扑排序优化

如题,超时了。

怎么办?

我们先用上图的例子。

我们把 \(fail\) 边拿出来。

如下。

显然,因为每个点都有 \(fail\) 边,然后 \(root\) 的边没了,所以就形成了一个 \(n-1\) 条边的连通图,就是树。

考虑在树上拓扑排序,用入度小的边更新入度大的边,就能不跳 \(fail\) 边统一更新答案。


参考资料:图解 AC 自动机,AC 自动机,题解:AC 自动机。


https://www.luogu.com.cn/article/3dm3m0aq

posted @ 2026-10-08 20:24  Ivan422  阅读(2)  评论(0)    收藏  举报