浅谈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 f