KMP
时间复杂度为O(n)的字符串匹配算法。
应用:
1.单一子串和模式串匹配
P3375 【模板】KMP字符串匹配
1 |
|
2.求最小循环节
SP263 PERIOD - Period
1 |
|
很显然,如果该字符串有循环节且$f[i]!=0$时$i-f[i]$即为该字符串的最小循环节。
3.求一个字符串所有相同的前后缀
P2375 [NOI2014]动物园
1 |
|
这道题不是单一的求一个字符串的答案,而是一个字符串所有前缀答案的乘积。但本质上还是对next数组的应用。
思考可得$next[i]$,$next[next[i]]$,$next[next[next[i]]]$,…都是前缀1~i的相等前后缀,递归统计即可。
然而如果输入n个’a’的时候,算法便被卡成了O(n^2)了,但我们发现每次递归都会有大量重复计算的相等前后缀,因此求完next数组后,再一次遍历整个字符串,不过这回我们不再把变量j从新赋值,接着用上一次的值,并判断其是否合法,这样便省掉了许多重复操作。
AC自动机
KMP+trie树
应用
1.多个模式串和主串进行匹配
P3808 【模板】AC自动机(简单版)
1 |
|
这位大佬的文章挺详细的。
P3796 【模板】AC自动机(加强版)
1 |
|
这道题新引入了一个优化,$l[x]$表示以节点x为结尾的后缀所包含的最长单词。这样就可以快速找到单词节点而不用一个一个的跳fail数组了。
P2292[HNOI2004]L语言
1 |
|
这道题也是一道多个模式串和主串进行匹配的题,我们只需在主串进行匹配的同时,判断是否能通过模式串到达该位置。
2.在fail树(或l树)上跑树形DP
P2414 [NOI2011]阿狸的打字机
1 |
|
1 |
|
这道题我们引入了fail tree。
- 在AC自动机中,我们知道,当我们从节点x出发一直沿着f指针进行跳跃直到0时,一路上所有单词节点都被包含在x在trie树中所表示的字符串中。
- 所以当我们想要找trie树中某一字符串y所包含的某一模式串x的次数时,我们便可以在trie树上从该字符串的结尾点向上跳,每跳一个,我们便要记录$f[y]$,$f[f[y]]$,$f[f[f[y]]]$,…,是不是单词节点x。
- 那问题如果反过来,询问一个模式串在其他几个模式串中出现过呢?
- 这时我们就想到了可以以每条fail为边建一颗fail tree(因为每个节点有且仅有一条fail边对应树中每个节点有且仅有一个父亲节点),此时我们可以直接统计以节点x为根的子树中有几个单词节点即可。
- 好了,现在回到这道题上,对于询问(x,y),我们可以从单词y所对应的节点在trie上一直跳父边到0,并在每一节点上加上1,最后只需统计单词x所对应的节点为根的子树中有多少1即可。(见暴力70分)
- 但是对于单词aaaab和aaaaaa等包含大量重复节点的询问,这样是非常浪费的,所以便有了正解中的第二遍在trie树上跑的dfs,这样便省去了多余的运算。
后缀自动机
将后缀树中相同结束位置的后缀节点合并为一个节点的最简状态自动机。
P3804 【模板】后缀自动机
1 |
|
一个节点x通过link连到初始点的路径的意义是该点所表示的最长字符串的后缀依次在状态$x,link[x],link[link[x]]…$中。具体学习请看hihocoder。
应用
1.求本质不同的子串个数
1445 : 后缀自动机二·重复旋律5
1 |
|
性质:每新加入一个字符,他都会对答案贡献 $ l[p]-l[link[p]] $
练习1:P4070 [SDOI2016]生成魔咒,与上一道实际上是同一道题。
练习2:P3975 [TJOI2015]弦论,将信息放在节点上,然后从根节点往下,每个点从’a’到’z’搜索。具体看代码。
练习一
1 |
|
练习二
1 |
|
2.求各子串出现的次数
1445 : 后缀自动机二·重复旋律5
1 |
|
在建完后缀自动机后, 可以先用桶排序将所有节点的长度进行排序,按倒序更新每个节点的size,但是这个size只是以当前节点为结尾的最长子串的出现次数,并没有更新它的后缀的出现次数;
这时就需要用到一个结论:长度小的子串出现的次数大于等于比它长的子串出现的次数。
然后只需在最后将ans与后一个取一个max即可。
3.求多个串之间的信息
1457 : 后缀自动机四·重复旋律7
1 |
|
将每个字符串之间用’:’连接成一个字符串并建立Sam,有一个显然的结论:对于一个节点(状态),能到达它的路径个数便是该节点(状态)中子串的个数。对于这道题我们特判一下,不遍历为’:’的边,因为一个字串的后缀和另一个字串的前缀组成的子串必定包含’:’。
练习:求n个字符串中本质不同的子串。
题解:同上,用’:’连接字符串统计即可。
4.求LCS(字符串匹配)
SP1811 LCS - Longest Common Substring
1 |
|
本文作者:
syrsteven
最后更新: 2023年09月02日 04:06:21
本文链接: http://syrsteven.github.io/post/b1c0144b.html
版权声明: 本作品采用 CC BY-NC-SA 4.0 许可协议进行许可,转载请注明出处!
最后更新: 2023年09月02日 04:06:21
本文链接: http://syrsteven.github.io/post/b1c0144b.html
版权声明: 本作品采用 CC BY-NC-SA 4.0 许可协议进行许可,转载请注明出处!