后缀数组题目
模板题 输出sa[i]
字符串的最小表示
将字符串s复制为ss,做后缀数组。
取首尾字符求字典序最小
P2870 [USACO07DEC]Best Cow Line G
题意
给出一个字符串,每次可以从字符串的首位取出一个字符,放到队列的尾部,求可以得到的最小的字典序是多少?
思路
pre[i]
表示以i开头的前缀(即把以i结尾的前缀倒过来)
suf[i]
表示以i开头的后缀
当str[l]!=str[r]
的时候取小的。
相等的时候直接比较pre[r]
和suf[l]
的排名
出现两次不重叠子串
题意
给出n个1-88组成的音符,让找出一个最长的连续子序列,满足以下条件:
- 长度大于5
- 不重叠的出现两次(这里的出现可以经过变调,即这个序列的每个数字全都加上一个整数x)
思路
我们处理一下这个所谓的“变调”:令a[i]=a[i+1]-a[i]
,这样就转化成了找最长的出现至少两次的相隔至少为1的不重叠子串。(这时长度变为n-1)
先二分答案,把题目变成判定性问题:判断是否存在两个长度为k的子串是相同的,且不重叠。解决这个问题的关键还是利用height数组。把排序后的后缀分成若干组,其中每组的后缀之间的height值都不小于k。例如,字符串为“aabaaaab”,当k=2时,后缀分成了4组,如图所示。
容易看出,有希望成为最长公共前缀不小于k的两个后缀一定在同一组。然后对于每组后缀,只须判断每个后缀的sa值的最大值和最小值之差是否不小于k。如果有一组满足,则说明存在,否则不存在。整个做法的时间复杂度为O(nlogn)。本文中利用height值对后缀进行分组的方法很常用,请读者认真体会
出现至少k次最长子串
题意
给出n个数字,以及一个k,求至少出现k次的最长子序列的长度
思路
和poj 1743思路差不多,二分长度,把后缀分成若干组,每组任意后缀公共前缀都>=当前二分的长度。统计是否有某个组后缀数量>=k,如果有当前长度就可以。
最长公共子串
题意
给出两个字符串,让找出最长的公共子串
思路
把两个字符串合起来,做最长不重叠子串即可。
找出最小循环节
题意
给出一个字符串s,求s最多由几个相同的字符串重复而成(最小循环节的重复次数)
思路
判断k是不是循环节,只需判断lcp(1,k+1)是否是n−k。
具体原理如下图:
对于lcp(1,k+1)
我们可以O(n)的预处理出所有height[i]到height[rank[1]]的最小值。
另外倍增会超时,要用到DC3算法,此算法复杂度为O(n)。
连续重复子串1
题意
给出一个字符串,求重复次数最多的连续重复子串。
题解 https://www.cnblogs.com/valk3/p/12880537.html
连续重复子串2
题意
SPOJ - REPEATS 的进阶版,在这题的基础上输出字典序最小的重复字串。
思路
跟上题一样,先求出最长的重复次数,在求的过程中顺便纪录最多次数可能的长度。
因为sa数组是按照字典序排好的,所以我们顺序遍历sa数组,枚举所有长度,判断当前连续长度是否等于最长的,找到第一个符合的输出。
长度不小于k的公共子串个数
题意
给出两个字符串,求他俩长度>=k的公共子串的数量。
本质不同子串个数
题意
给出T个字符串,问每个字符串有多少个不同的子串。
思路
按照后缀排序,遍历后缀,每次新增的前缀就是除了 与上一个后缀的所有公共前缀 之外的前缀。
答案就是用总数-重复的 即(frac{n(n+1)}{2}-sum_{i=1}^{n}height[i])