前置:
- 后缀自动机SAM基本概念:https://blog.csdn.net/Jaihk662/article/details/82823251
- 后缀自动机线性构造方法:https://blog.csdn.net/Jaihk662/article/details/82824469
题目&讲解:http://hihocoder.com/problemset/problem/1449
问题一:如何求出Suffix Links每个节点的endpos()大小
先拉出3条性质,这两条性质在先前blog都有提及
- 对于所有同一个节点的子串,一定满足集合endpos()相同,除此之外,endpos()相同的所有子串一定属于同一个节点,并且这些字符串是一段连续的后缀
- 所有的Suffix Links构成了一颗根节点为0的内向树,如果u的v的父亲,那么满足v一定是u的子集(默认指节点的endpos)
- s1是s2的后缀当且仅当endpos(s2) ⊆ endpos(s1),s1不是s2的后缀当且仅当endpos(s1) ∩ endpos(s2) = ∅
有些东西是求不出来的,例如你无法求出所有节点的endpos集合所有元素,因为元素个数是O(len²)的,除此之外,|endpos()|不能动态更新,因为每插入一个字符,最坏情况下所有的节点的endpos都会被改变,例如全a字符串
→所以你只能在字符串插入结束后,静态求出所有节点的|endpos()|,也就是每个节点endpos()元素个数
那么每个节点的|endpos()|怎么求
一些推导性质:
- 由上面性质③可得:如果u是v的父亲,那么一定满足endpos(v) ⊂ endpos(u),除此之外如果两个节点u, v不满足其中一个是另一个的祖先,那么endpos(u) ∩ endpos(v) = ∅
- 由上可得:对于节点u,如果节点u不包含子串S[1..i],也就是不存在母串的某个前缀,那么满足|endpos(u)| = ∑|endpos(son(u))|,其中son(u)为u点的所有儿子,否则|endpos(u)| = ∑|endpos(son(u))|+1
由推导性质,就可以轻松在线性时间内求出所有节点的|endpos()|了
问题二:给你长度为n的母串,对于每一个的k∈[1, n],求出所有长度为k的子串中出现次数最多的子串出现次数
很显然先要求出所有节点的|endpos()|
如果|endpos(u)| = 15,这就说明节点u所有的子串都出现了刚好15次,这样的话,假设|endpos(u)| = 15,len(u) = 18,这就说明所有长度≤18的子串中出现次数最多的子串出现次数一定≥18
步骤如下:
- 求出SAM,并建出Suffix Links
- 对Suffix Links进行DFS时求出所有节点的|endpos()|
- 在如上过程中求出 ans[k] 表示长度≤k的子串中出现次数最多的子串出现次数的最小值
- 对ans[]求一遍后缀最大值就是答案
题目&代码:https://blog.csdn.net/Jaihk662/article/details/82830607