AC 自动机(ACAM)
libohan0905 · · 个人记录
前置芝士:trie(字典树)
题单
闲话
因为不会德文的这题来学的。
因为笔者也只能速通 ACAM,难免有错漏之处。希望各位大佬不吝赐教,蒟蒻再次拜谢。
引入
学习 AC 自动机的第一要义:它不能帮你自动 AC!
AC 自动机(英文名为 Aho-Corasick automaton,以下简称 ACAM),是一种多模式串匹配算法,它是由贝尔实验室的两位研究人员 Alfred V. Aho 和 Margaret J.Corasick 于 1975 年发明。
KMP 算法则是常用的单模式串匹配算法。无法高效解决在一段文本串中一次性匹配多个模式串的问题。
定义
- 失配:没有匹配上。
- fail 边:失配时应该转移的边,类似于 KMP 的 next 数组。
- fail 树:fail 边所构成的树。
- 文本串:用于被查找的串,一般很长。
- 模式串:从文本串里查找的串。
-
简介
ACAM 是结合了 KMP 的失配指针和 trie 的树形结构的一种算法。俗称“KMP 上 trie”。但事实上和 KMP 区别不少。
建 ACAM 需要在 trie 上建边。一般称为“补 trie 图”(加边后就变成图了)。加的边是 fail 边,每个节点都有一条往外的 fail 边,令 trie 上从根节点到这个节点的字符串为
建 fail 边比较难以解释 其实是窝不会。这里丢几个比较详细的链接。
- yyb巨佬的博客
- AC 自动机
- 强势图解AC自动机
- 算法学习笔记(89): AC自动机
相信各位应该都会建 fail 边了(即建立 ACAM)。fail 边到底是干什么用的?
比如 trie 上有一个
我们再讲一个东西叫 fail 树。
所有 fail 边单独看又构成一棵 fail 树。fail 树怎么建?只要把所有 fail 边反向连起来就建好了。它在我们需要多次暴力跳 fail 边时可以把它拎出来配合树上技巧来优化。
比如:统计串
解释一下:把 trie 上
我们通过模板题来了解一下。
P3796 【模板】AC 自动机(加强版)
- 有
N 个由小写字母组成的模式串以及一个文本串T 。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T 中出现的次数最多。保证不存在两个相同的模式串。 -
先把所有模式串建立一个 trie,然后建立 fail 边。
我们在 trie 上把每个字符串末尾打标记。然后把文本串放到 trie 上去遍历,对于每个被遍历到的点,我们都暴力跳 fail 直到根,如果遇到一次打标记的点就说明遇到一次,根据对应标记增加其出现次数。
虽然这题可以过,但是复杂度比较劣。是文本串乘模式串。代码。
考虑操作的本质:文本串每个点的贡献增加是从这个点到根的一条链。使用树上差分的思想最后对 fail 树一遍 dfs 即可。复杂度降至线性。代码。利用这种思想可以做二次加强版。
P5231 [JSOI2012] 玄武密码
- 给你
1 个长为n 的文本串T ,m 个模式串S_i 。对于每个S_i ,求它最长的是T 子串的前缀。 -
建 trie 时把所有点的深度和父亲记录下来,把每个串的末尾记录下来。
把文本串所有点都暴力跳 fail 边,标记所有经过的点。
询问的时候从串的末尾往父亲找,第一个有标记的点的深度就是答案(有标记意味着出现过,第一个意味着深度最大)。
因为数据水所以过了。事实上,这种做法可以被字母全部相同的
其实加个简单的剪枝即可。如果这个点已经被打标记了,那么它上面的所有点肯定也被打标记了,就不用再跳 fail 边了。这样每个点最多被打一次标记,复杂度为
CF547E Mike and Friends
- 给定
n 个字符串s_{1 \dots n} 。 -
-
题解
考虑 AC 自动机。
先把所有串的 trie 树建出来,再把 fail 树建出来。
题目求
像扫描线的思路把询问排序。考虑一个一个插入字符串。每个串会增加 trie 上经过的点的贡献。
询问就是 fail 树的子树权值和。
操作有:
- 增加一些点的权值。
- 统计 fail 树的子树内的权值和。
可以使用 dfs 序配合树状数组求解。
由于字符串的总长度是有限制的,所以每个字符串暴力跳每个点复杂度是有保证的。
时间复杂度
相关习题
- 弱化版:P3966 [TJOI2013] 单词。
- 变式:P2414 [NOI2011] 阿狸的打字机。
注意没有限制
\sum |s| ,所以统计贡献时应该按照构造字符串的顺序才能保证复杂度。 - 变式:CF1207G Indie Album 把询问挂在树的节点上。
参考资料
- yyb巨佬的博客
- AC 自动机
- 题解 CF547E 【Mike and Friends】