后缀自动机Suffix Links的应用

版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/82829707

前置:

题目&讲解:http://hihocoder.com/problemset/problem/1449

 

问题一:如何求出Suffix Links每个节点的endpos()大小

先拉出3条性质,这两条性质在先前blog都有提及

  1. 对于所有同一个节点的子串,一定满足集合endpos()相同,除此之外,endpos()相同的所有子串一定属于同一个节点,并且这些字符串是一段连续的后缀
  2. 所有的Suffix Links构成了一颗根节点为0的内向树,如果u的v的父亲,那么满足v一定是u的子集(默认指节点的endpos)
  3. s1是s2的后缀当且仅当endpos(s2) ⊆ endpos(s1),s1不是s2的后缀当且仅当endpos(s1) ∩ endpos(s2) = ∅

有些东西是求不出来的,例如你无法求出所有节点的endpos集合所有元素,因为元素个数是O(len²)的,除此之外,|endpos()|不能动态更新,因为每插入一个字符,最坏情况下所有的节点的endpos都会被改变,例如全a字符串

→所以你只能在字符串插入结束后,静态求出所有节点的|endpos()|,也就是每个节点endpos()元素个数

那么每个节点的|endpos()|怎么求

一些推导性质:

  1. 由上面性质③可得:如果u是v的父亲,那么一定满足endpos(v) ⊂ endpos(u),除此之外如果两个节点u, v不满足其中一个是另一个的祖先,那么endpos(u) ∩ endpos(v) = ∅
  2. 由上可得:对于节点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

步骤如下:

  1. 求出SAM,并建出Suffix Links
  2. 对Suffix Links进行DFS时求出所有节点的|endpos()|
  3. 在如上过程中求出 ans[k] 表示长度≤k的子串中出现次数最多的子串出现次数的最小值
  4. 对ans[]求一遍后缀最大值就是答案

题目&代码:https://blog.csdn.net/Jaihk662/article/details/82830607

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/82829707