AC自动机
AC自动机
要学AC自动机需要自备两个前置技能:KMP和trie树 其中,KMP是用于一对一的字符串匹配,而trie虽然能用于多模式匹配,但是每次匹配失败都需要进行回溯,如果模式串很长的话会很浪费时间,所以AC自动机应运而生,如同Manacher一样,AC自动机利用某些操作阻止了模式串匹配阶段的回溯,将时间复杂度优化到了\(O ( n )\),n为文本串长度
问题描述
给定n个模式串和11个文本串,求有多少个模式串在文本串里出现过。
注意:是出现过,就是出现多次只算一次。
我们将n个模式串建成一颗Trie树,建树的方式和建Trie完全一样。
预处理:Tire树的构建
构建如下,绿色表示终止,不懂可以看前几篇博客
Fail指针
3个原则:
1.构建fail指针的层次遍历
2.root节点的fail指针指向自己本身
3.如果当前父节点的fail指针指向的节点存在与当前节点一样的子节点,则当前节点的fail种子很指向该节点。
毫无疑问
root指向自己
s和h指向root,因为s的父节点根节点并没有与当前节点一样的节点,因为不会重复,这就是为什么第一层都是指向根节点查的原因。
接下来a节点,他的父节点是s,s指向的fair为根,并没有指向a,因此也指向根节点。
而h得父节点s也指向根节点,根节点有指向h得,因此h就指向h,如图:
同理,e也指向root,y也是root,e父节点是h,h指向上面的h,上面的h指向的是e,因此有了
其实这里已经可以看出Fail的实质含义:
如果一个点i的Fail指针指向j。那么root到j的字符串是root到i的字符串的一个后缀。
首先我们可以确定,每一个点i的Fail指针指向的点的深度一定是比i小的。(Fail指的是后缀)
AC 自动机(简单版)
题目描述
给定 \(n\) 个模式串 \(s_i\) 和一个文本串 \(t\),求有多少个不同的模式串在文本串里出现过。
两个模式串不同当且仅当他们编号不同。
输入格式
第一行是一个整数,表示模式串的个数 \(n\)。
第 \(2\) 到第 \((n + 1)\) 行,每行一个字符串,第 \((i + 1)\) 行的字符串表示编号为 \(i\) 的模式串 \(s_i\)。
最后一行是一个字符串,表示文本串 \(t\)。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
1 | 3 |
样例输出 #1
1 | 3 |
样例 #2
样例输入 #2
1 | 4 |
样例输出 #2
1 | 3 |
样例 #3
样例输入 #3
1 | 2 |
样例输出 #3
1 | 2 |
提示
样例 1 解释
\(s_2\) 与 \(s_3\) 编号(下标)不同,因此各自对答案产生了一次贡献。
样例 2 解释
\(s_1\),\(s_2\),\(s_4\) 都在串 abcd
里出现过。
数据规模与约定
- 对于 \(50\%\) 的数据,保证 \(n = 1\)。
- 对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 10^6\),\(1 \leq |t| \leq 10^6\),\(1 \leq \sum\limits_{i = 1}^n |s_i| \leq 10^6\)。\(s_i, t\) 中仅包含小写字母。
1 |
|