【学习笔记】后缀数组(2)

后缀数组学习笔记(2)


后缀数组有多种多样的搞法,这里选讲几道。下文中,部分题目&思路来自论文。

Luogu P4051 [JSOI2007]字符加密

链接

题意:给出一个字符串,假定其长度为\(len\),按照环的方式读出\(len\)个字符串,将其从小到大排序,依次输出最后一个字母,\(len \le 10^5\)

题解:后缀数组的直接运用。

看到环,我们可以想到将其破环为链,得到一个长度为\(len\times2\)的字符串,将其用后缀数组求出所有后缀的顺序,我们就得到了长度为\(len\)的后缀的顺序(只按照了字符串顺序排序,如果相同,顺序是按照其所在后缀的大小排序的)。从小到大遍历\(sa\)数组,若\(sa_i<len\)(从0开始的情况下),就输出末位字母,也就是\(sa_i+len-1\),就得到了答案。

单个字符串问题

此种题目的一个常用做法是先求后缀数组和 \(height\) 数组,然后利用 \(height\)数组进行求解

Luogu 2743 [USACO5.1]乐曲主题Musical Themes

(POJ1743,本题数据范围缩小了点)

题目链接 题意:给出\(N\)个数,求出不重叠的最长的重复子串。(若长度不足\(5\),输出\(0\)

注意:一个子串为另一个子串加或减同一个数,这两个子串仍然相同。

题解:先来考虑不重叠最长重复子串问题,我们可以用二分答案使之变为判定性问题。假如当前判断的长度为\(k\),那么对于两个后缀,假如它们中间存在一个i,且\(height_i<k\),答案不在这两个字符串中。

那么,我们可以分成若干组,每组中的\(height\)都大于等于\(k\),如下图。当一组中存在两个数\(i\),\(j\),使得\(sa_i+k-1<sa_j\),则存在答案为\(k\)的不重叠的重复子串。

回归本题,我们可以用差分的方法解决所谓的转调,然后按上面的方法做。

由于细节较多,放上代码


Luogu P2852 [USACO06DEC]牛奶模式Milk Patterns

链接 题意:给出\(N\)个数,求出最长的可重叠的重复\(x\)次的子串的长度。

题解:我们同样使用二分答案使其变为判定性问题。

我们同样在二分后进行分组,如上图所示,设现在判定的长度为\(k\)。容易发现,每一组中都必然有一个长度为\(k​\)或更大的,共同的前缀。

所以,如果组内后缀个数\(\ge x\),即有满足条件的长度为\(k\)的前缀。二分求出其最大值即可。


参考资料:

[1] 罗穗骞,IOI2009 国家集训队论文《后缀数组——处理字符串的有力工具》2009.1

posted @ 2019-01-23 15:23  fmj_123  阅读(257)  评论(0编辑  收藏  举报