浅谈AC自动机
建议学过 AC 自动机的人来看。
注意我们一开始直接建立串的时候是 T r i e \tt Trie Trie 图,之后建立 f a i l \tt fail fail 指针的时候才是真正的 A C AC AC 自动机。
具体来说对于 T r i e \tt Trie Trie 上深度从小到大的一条链,对应的是一个曾经在某个或者多个串中出现过的子串。
如果说是一条从根到底的链那本质就是代表一个串,显然对于一条链之间的点,本质上深度小的是深度大的前缀串。
用处:
- 我们可以通过遍历 T r i e \tt Trie Trie 图来不重复地遍历每个字符串(不会有相交)。
还有一个东西叫 f a i l \tt fail fail 树,这个东西的定义和 n x t \tt nxt nxt 数组很类似,就是与当前串公共后缀最长的点。
那么我们一直沿着 f a i l \tt fail fail 树跳的话是可以遍历到所有与当前串后缀部分有交的串,而且是交是从大到小的。
注意:
-
我们进行找 f a i l \tt fail fail 指针的时候需要使用路径压缩,但是即使使用了路径压缩,我们直接建立 f a i l \tt fail fail 树的时候完全不会有影响。
-
如果说拿节点 1 1 1 当做超级源点的话,对于周围一圈的不存在的点,需要路径压缩至点 1 1 1。
用处:
- 发现对于一个节点 x x x,在 f a i l \tt fail fail 树上的子树中的所有节点都是后缀包含其的节点。可以通过打标记,进行子树求和来得到该节点(字符串)出现的次数。
简单例题
容易看出题目给的输入,就是建立 T r i e \tt Trie Trie 的方式。我们建立 f a i l \tt fail fail 树。
之后考虑 ( x , y ) (x, y) (x,y) 我们可以通过枚举 y y y 中的每一个点,判断其 f a i l \tt fail fail 树上的祖先是否有 x x x 的终止节点。
那么我们可以考虑遍历完所有的 y y y 节点的时候,在 f a i l \tt fail fail 树上的 x x x 处,统计子树和。
发现因为我们遍历子串是通过 T r i e \tt Trie Trie 的,所以不同的字符串可以一起做,直接离线即可。
#include <bits/stdc++.h>
using namespace std;
namespace Legendgod {

本文介绍了AC自动机的概念,强调了从Trie图到AC自动机的构建过程,特别是fail指针的作用。AC自动机可以无重复地遍历所有字符串,并通过fail树获取字符串公共后缀。文章还讨论了路径压缩在构建fail树中的应用,以及如何利用fail树进行子树求和以计算字符串出现的次数。通过一个NOI2011的例题,展示了AC自动机在解决字符串问题上的应用。
最低0.47元/天 解锁文章
217

被折叠的 条评论
为什么被折叠?



