[复习]字符串
纯复习内容,内容比较粗糙。
字符串哈希
最基本的东西,一般而言并不太需要注意哈希被卡的问题。
个人比较习惯的是单哈希、自然溢出。偶尔会使用多模数哈希,但还是用自然溢出。
可以用来干的事情:快速判断两个串是否相等,判断回文串等。
比较容易实现,不多写了。
最小循环表示法
(lun)讲过了好多次了嗷。。。。
这个东西是啥?参考一道题目【洛谷1368/BZOJ2882】工艺。
显然存在一个直接构建(SAM)然后按照字典序跑的做法。
这里有个简单的做法:定义两个指针(i,j)。初始时(i=1,j=2)。
然后两个指针不断向后匹配,直到扫到两个字符不相等,假设前面相等的长度为(k)。
如果(S[i+k]<S[j+k]),那么显然(j)在这一段之间一直不优,所以令(j=j+k)。否则(i=i+k)。
如果做完上述操作之后两个数相等,则强制一个向后移动即可。
(KMP)算法
很久以前写的博客
重新谈谈。
(KMP)的(next)数字到底是啥呢?(border)。即前缀等于后缀。
(next)的含义就是以当前位置结尾的最长(border)。
知道了这个那么(next)数组很容易求,假设当前要求的结尾位置为(i)。那么它可能达到的最长(border)为(next[i-1]+1),如果可行就做完了。否则只能找(i-1)的(border)的最长(border)了,那么就循环处理。最后的特殊情况下(border)可以为(0)。
利用(next)匹配求解答案的时候类似,一旦匹配不上就考虑能否从(border)位置开始匹配。
(AC)自动机
显然原来也是写过的
再来口胡一遍。
AC自动机可以理解为是(KMP)的多串版本。
大致的做法是把所有串构建(Trie),定义(fail)指针表示当前节点表示的串中的在(Trie)树上的最长(border)的位置。这样子每次失配的时候直接暴跳(fail)即可。
(fail)指针的构建方法是(bfs)。
一般而言会有两种不同的(AC)自动机,一种就是最普通的,另外一种是(Trie)图。(Trie)图是所有转移即目标节点构成的图。如果需要在(AC)自动机上面进行(dp)相关操作,(Trie)图是更加合适的选择。
然后大概归类一下(AC)自动机的相关题目类型:
首先是纯匹配类型的,完全就是看自己对于(AC)自动机的理解,比如这题、还有这题。这类题目很多,专注于对于(AC)自动机的理解是关键。
第二类是(AC)自动机上面(dp)。而(dp)的问题一般是一些串不能出现在答案串中的方案数,或是必须出现在答案串中的方案数之类的。做法就是构建(Trie)图,然后在上面匹配。如果是不能出现,那就是有些点不能被访问到,如果是必须出现,那么就状压记录串的出现情况。转移沿着(Trie)图走就行了,并且如果串长之和很小还可以矩乘。题目随便找几道吧。这个、这个、这个。
第三类是和(fail)树相关的东西,这一类单独拿出来是因为后面的(SAM)和(PAM)都有这一类的问题。主要是这题。利用(fail)树加上一些统计子树内询问的方法来解决问题。
其他的还有一些奇怪的东西,比如二进制分组+(AC)自动机之类的,这里就不提及了。
(manacher)
原来都写过啊 。
维护回文中心,利用回文的形式来快速求解。
代码和思想都比较简单,用途不是很多,就不讲了。
后缀数组
戳这里
按照二元组的倍增排序。
后缀数组能够做的,(SAM)基本都能做,当然也有些东西(SAM)做起来没那么方便。
所以(SA)还是要会的。
为了复习随手写了道题目戳这里。
回文树
似乎回文树就是回文自动机吧?原来也写过QwQ
关于回文串的一些计数问题,回文树和(manacher)各有利弊。回文树求出来的是以当前位置结尾的回文后缀的个数,而(manacher)求出来的是每个回文中心能够延伸出去的回文半径。用哪个因题而异。
是在是找不到太多很有意义的题目。
不过有一道和回文树性质相关的题目。【CF932G】。
给回文树中每个节点定义一个(dif),表示其和父亲的(len)的差。
定义(anc)表示所有祖先中,第一个与其(dif)不相同的祖先。
可以证明把当前点到根节点的所有(dif)拿下来一定是一段段的等差数列。并且每个点如果沿着(anc)走到达根节点的次数不会超过(log)次。对于沿着回文树(fail)树上的(dp)转移,可以利用上述性质优化。
这个玩意支持前端插入后端插入,前端删除,后端删除,但是不常见,所以不太会。
后缀自动机
戳这里
板子什么的背背就好了。但是每个节点表示的是什么,性质之类的,一定要记牢。
毕竟这个玩意的运用太广了。
然后如果只要求解(right)集合的大小的话,拓扑序向上合并就好了。
如果要求(right)集合的话,线段树合并维护。
还有如果要支持动态维护(right)集合大小的操作的话可以(LCT),题目似乎是【BZOJ2555】。
还可以套上各种各样的东西。
还有就是两个串的(lcp)就是他们在(SAM)上所代表的节点在(parent)树上的(LCA)的(len)。
主要就这些吧。
这里的变化还是挺多的。