后缀数组应用小结

#前言#
之前学了后缀数组,这真是一个神奇的东西。早就想总结一些SA的应用,但一直没时间,现在终于抽出空来写一下自己的心得。
本文只讨论后缀数组的一些应用,不一定全面,仅供参考
还不会后缀数组的同学请自学后再看本文,这里不再赘述后缀数组的基础实现
推荐一篇博客,里面对于基础的后缀数组总结的比较到位,YxuanwKeith大神的五分钟搞懂后缀数组!后缀数组解析以及应用
请不要吐槽标题,不知道你五分钟搞不搞得懂,反正我搞不懂 = = 。
下面进入正题。


#后缀数组相关应用#
##单个字符串相关问题##
比较常见的思路是先构造后缀数组,然后求Height数组,用这两个来求解。
###重复子串问题###
####可重叠的最长重复子串问题####
因为可重复,所以这类问题比较简单。只需要求 H e i g h t Height Height数组的最大值。因为 H e i g h t [ i ] Height[i] Height[i]表示排名为 i i i i − 1 i-1 i1的后缀的LCP,所以这个LCP一定是重复的,只需要求个最大值就是最长的。时间复杂度是线性的。
####不可重叠的最长重复子串问题####
有了不可重叠的限制稍微复杂一点,要用到 H e i g h t Height Height数组的性质。先二分答案,将问题转化为判定性问题。假设我们二分的长度为 k k k,那么答案的两个串它们在SA中的之间的 H e i g h t Height Height值都会 ≥ k \geq k k(想一想为什么?),所以我们把连续一段 H e i g h t ≥ k Height \geq k Heightk的后缀划分成一段,如果有某一段满足段中最大的SA值与最小值之差大于等于 k k k,那么当前解就是可行的,因为满足这一条件的串一定不重叠。
注意:这种分段的思想在后缀数组相关问题中很常用
####可重叠的 k 次最长重复子串####
例:(JZOJ2265. 【Usaco DEC06 Gold】Milk Patterns)给定一个字符串,求至少出现 k 次的最长重复子串。
做法和上面的差不多,还是先二分,但是条件改变了,不是不重叠,而是出现至少 k k k次。只需判断当前段内是否出现 k k k个后缀即可。
###子串计数问题###
####重复出现子串计数问题####
例:(JZOJ1598. 文件修复)求一个字符串中有多少个至少出现两次的子串
这是比较简单的SA题,设每个后缀 R a n k Rank Rank i i i,其最多能贡献 H e i g h t [ i ] − H e i g h t [ i − 1 ] Height[i] - Height[i-1] Height[i]Height[i1]个不同重复子串。
∴ A n s = ∑ m a x ( H e i g h t [ i ] − H e i g h t [ i − 1 ] , 0 ) \therefore Ans = \sum max(Height[i]-Height[i-1],0) Ans=max(Height[i]Height[i1],0)
####不相同子串计数问题####
例:(spoj694,spoj705)给定一个字符串,求不相同的子串的个数。
和上面思路大相径庭。每个后缀 k k k会产生$n-SA[k]+1 个 前 缀 , 但 是 会 重 复 计 数 , 所 以 要 减 去 前 面 相 同 的 前 缀 , 最 后 就 是 个前缀,但是会重复计数,所以要减去前面相同的前缀,最后就是 n-sa[k]+1- height[k]KaTeX parse error: Expected 'EOF', got '#' at position 6: 个子串。 #̲###字典序第K子串问题###…S 长 度 长度 k , 如 果 ,如果 Rank[1] 和 和 Rank[k+1] 的 的 Height=|L|-kKaTeX parse error: Expected 'EOF', got '#' at position 11: 那么当前答案合法。 #̲###重复次数最多的连续重复子…L , 求 重 复 次 数 最 多 的 连 续 重 复 子 串 。 还 是 枚 举 子 串 长 度 ,求重复次数最多的连续重复子串。 还是枚举子串长度 k , 看 这 个 长 度 对 应 每 个 位 置 ( 即 ,看这个长度对应每个位置(即 L[0],L[k],L[k*2]… ) 之 间 的 L C P 是 否 等 于 )之间的LCP是否等于 LCPkKaTeX parse error: Expected 'EOF', got '#' at position 19: …扩到哪里,就是重复出现次数。 #̲#多个字符串相关问题## 常用…N 个 字 符 串 , 求 每 个 字 符 串 在 所 有 字 符 串 中 出 现 的 次 数 。 对 于 当 前 字 符 串 个字符串,求每个字符串在所有字符串中出现的次数。 对于当前字符串 S , 设 其 在 总 串 中 起 始 位 置 为 ,设其在总串中起始位置为 ST[i] , 那 么 我 们 在 ,那么我们在 Height 上 二 分 区 间 上二分区间 [1,Rank[ST[i]]],[Rank[ST[i]]+1,n] 内 满 足 内满足 Height\geq|S|KaTeX parse error: Expected 'EOF', got '#' at position 16: ,这之间的后缀数量就是答案。 #̲##字符串子串重复出现k次问题…n 个 操 作 , 每 个 操 作 在 字 符 串 个操作,每个操作在字符串 S$尾插入一个字符,求当前操作后共有多少不同种连续子串。
仔细分析,这题要减去前面的操作对当前影响(即重复的连续子串)。这个应该算是“前缀数组”吧。具体来说就是将字符串翻转后求一边SA,此时所得就是原串的前缀数组。然后在线段树维护一下。


#后记#
这篇博客是在复习之余码的,由于水平有限,难免有疏漏之处,欢迎批评和补充。后续(或许)会有例题及应用的补充。
参考资料:罗穗骞《后缀数组——处理字符串的有力工具》

以上.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值