OI loves Algorithm——后缀数组

最近 NFLS 周赛,F 题需要后缀数组,我不会,光荣掉到 20+ 名。

打完后就去补习了相关知识,觉得很巧妙,就来写了一篇专栏

1. 后缀数组的定义

后缀数组(SA)保存的是一个字符串所有后缀的排序结果,其中第 SA[i] 表示所有后缀中第 $ i $ 小的后缀的开头位置

与之相对的是名次数组 Rank,Rank[i] 表示以 $ i $ 开头的后缀排第几位

举个栗子:

str: a a a b a a b a
SA:  8 1 5 2 6 3 7 4
Rank:2 4 6 8 3 5 7 1

2. 求法

有两种方法倍增和 DC3,但我太菜了,只会倍增算法。

2.1. 倍增

倍增,就是通过 $ i $ 步的答案推出 $ 2i $ 步的答案,从而在 $ O(\log n) $ 的时间内推出答案。那它跟后缀数组有什么关系呢?

假设我们已经求出了每个 $ i \sim i + 1 $ 的子串的 Rank:

str: a a a b a a b a
Rnk2:2 2 3 4 2 3 4 1

考虑将两个字符和两个字符拼在一起成为四个字符。

实际上,我们只需要将 Rank 拼在一起即可。为什么呢?

考虑将这样的二元组进行比较:

aaab Rank: (2, 3)
aaba Rank: (2, 4)
因为 Rank 反映了字典序情况,所以比较 Rank 相当于比较字典序
First: 2 = 2 相当于比较前两个字符的字典序
Second:2 < 4 相当于比较后两个字符的字典序

回到我们刚才的例子:

Rnk2:2 2 3 4 2 3 4 1
1st: 2 2 3 4 2 3 4 1
2nd: 3 4 2 3 4 1 0 0 (没有时视为 0,是最小的序列)
Rnk4:2 3 5 7 3 4 6 1

于是我们就不断把子串拼接拼接再拼接,拼接足够多次直到长度 $ \ge n $ 即可。

使用基数排序,我们就可以 $ O(n \log n) $ 求出答案。

2.2. DC3

<++>(待更)

3. 实际应用

<++>(待更)

posted @ 2024-07-10 18:22  A-Problem-Solver  阅读(3)  评论(0编辑  收藏  举报