OI loves Algorithm——字尾陣列

A-Problem-Solver發表於2024-07-10

最近 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. 實際應用

<++>(待更)

相關文章