后缀数组
后缀数组
后缀数组(Suffix Array),主要关系到两个数组
显然,
O(n\log^2{n}) 求法
-
对所有长为 1 的子串排序
-
对所有长为 2 的子串排序(以
rk_i 为第一关键字,rk_{i+1} 为第二关键字) -
对所有长为 4 的子串排序(以
rk_i 为第一关键字,rk_{i+2} 为第二关键字) -
以此类推
如果每次 sort,总时间复杂度
O(n\log{n}) 求法
考虑用基数排序优化 sort。即按照先排第二关键字确定初步的相对顺序,再根据第一关键字排序。(内部用桶排)
Height
证明:
设后缀
则后缀
实际
通过结论 1 可以
for (int i = 1, j = 0; i <= n; i ++) {
if (j) j --;
while (sa[rk[i]] + j <= n && sa[rk[i] - 1] + j <= n && s[sa[rk[i]] + j] == s[sa[rk[i] - 1] + j]) j ++;
height[rk[i]] = j;
}
结论2:
应用
- 本质不同子串的数
子串就是后缀的前缀,所以可以枚举每个后缀,计算重复的前缀总数,用总方案减掉重复的方案。
所以答案应为:
[SDOI2016] 生成魔咒
对每个前缀求,本质不同的子串数。
考虑在字符串末尾插入一个新字符,最多会有
若是在字符串首部插入一个字符,最多只有包括前驱、后继的
每次加入一个字符,可以获得一个新的后缀,它的排名是
- 出现次数大于等于
k 的最长子串
[USACO06DEC] Milk Patterns G
求出 height 序列,然后以长度为
[TJOI2019] 甲苯先生和大中锋的字符串
要求出现次数恰好为
- 多串的最长公共子串
[SDOI2008] Sandy 的卡片
先把所有串中间加一个分隔符连起来。
二分答案 mid,只去 height>=mid 的部分,若有一个极长连续段包含了每个串的元素作为后缀的开头,则满足条件。
- 连续相同子串
优秀的拆分
考虑如何统计形如
枚举
考虑两个相邻特殊点
令
那么如图那一段黄色都可以表示为