摘抄自quack的ppt。
這部分和 s a sa sa的關聯比較大,可以加深對 s a sa sa的理解。
Part 1
如果字符串 s s s的字典序在 s s s以及 s s s的所有后綴中是最小的,則稱 s s s是一個 lyndon \text{lyndon} lyndon串。
lyndon \text{lyndon} lyndon分解,指的是把一個字符串分成若干段,每一段都是一個 lyndon \text{lyndon} lyndon串,問最少的分割段數。
方法一:用后綴數組, s a [ 1 ] sa[1] sa[1]就是 lyndon \text{lyndon} lyndon分解的最后那一段, lyndon \text{lyndon} lyndon分解倒數第二段就是把 s a [ 1 ] sa[1] sa[1]那一段排除之后排的最靠前的 s a sa sa,以此類推。
s a sa sa可以用來 lyndon \text{lyndon} lyndon分解依賴于以下結論:
定義數組 a [ i ] a[i] a[i]為最小的 j j j,使得 j > i j>i j>i且 S [ j : ∣ S ∣ ? 1 ] < S [ i : ∣ S ∣ ? 1 ] S[j:|S|-1]<S[i:|S|-1] S[j:∣S∣?1]<S[i:∣S∣?1],如果不存在這樣的 j j j,可以認為 a i = ∣ S ∣ a_i=|S| ai?=∣S∣。
那么, S S S的 lyndon \text{lyndon} lyndon分解的第一項為 S [ 0 : a [ 0 ] ? 1 ] S[0:a[0]-1] S[0:a[0]?1],且后面 m ? 1 m-1 m?1項就是 S [ a [ 0 ] : ∣ S ∣ ? 1 ] S[a[0]:|S|-1] S[a[0]:∣S∣?1]的 lyndon \text{lyndon} lyndon分解。
證明:顯然此時不能劃分到 a [ 0 ] a[0] a[0]之后,否則可以根據原串后綴的信息道出矛盾。因此只需論證劃分到 a [ 0 ] a[0] a[0]合法即可。注意到此時 S [ a [ 0 ] ] ≤ S [ 0 ] S[a[0]]\le S[0] S[a[0]]≤S[0],因此對于任意 j ∈ [ 1 , a [ 0 ] ? 1 ] j\in [1,a[0]-1] j∈[1,a[0]?1],一定滿足 S [ 0 : a [ 0 ] ? j ? 1 ] ≠ S [ j : a [ 0 ] ? 1 ] S[0:a[0]-j-1]\ne S[j:a[0]-1] S[0:a[0]?j?1]=S[j:a[0]?1],又因為 s a [ 0 ] < s a [ j ] sa[0]<sa[j] sa[0]<sa[j],因此 S [ 0 : a [ 0 ] ? 1 ] S[0:a[0]-1] S[0:a[0]?1]一定是它的所有后綴當中最小的。
基本性質:
1.1 1.1 1.1 若字符串 u , v u,v u,v是 lyndon \text{lyndon} lyndon串且 u < v u<v u<v,則 u v uv uv是 lyndon \text{lyndon} lyndon串。
1.2 1.2 1.2 若字符串 s s s是 lyndon \text{lyndon} lyndon串, s ′ a s'a s′a是 s s s的前綴,那么 s ′ b ( b > a ) s'b(b>a) s′b(b>a)是 lyndon \text{lyndon} lyndon串。(注意 s ′ a s'a s′a不一定是 lyndon \text{lyndon} lyndon串)
方法二:duval 算法
每次維護一個前綴的 lyndon \text{lyndon} lyndon分解。這個前綴 S [ 1 : k ? 1 ] S[1:k-1] S[1:k?1]可以被分解成 s 1 , . . . , s g s_1,...,s_g s1?,...,sg?這些 lyndon \text{lyndon} lyndon串和 S [ i : k ? 1 ] S[i:k-1] S[i:k?1]這個近似 lyndon \text{lyndon} lyndon串(形如 w k w ′ w^kw' wkw′, w w w是一個 lyndon \text{lyndon} lyndon串, w ′ w' w′是 w w w的前綴)。
具體的,三個變量 i , j , k i,j,k i,j,k維持一個循環不變式:
- S [ 0 : i ? 1 ] = s 1 s 2 . . . s g S[0:i-1]=s_1s_2...s_g S[0:i?1]=s1?s2?...sg? 是已經固定下來的分解,滿足 s l s_l sl?是 lyndon \text{lyndon} lyndon串,且 s l ≥ s l + 1 s_l\ge s_{l+1} sl?≥sl+1?(否則可以合并)。
- S [ i : k ? 1 ] = t 1 t 2 . . . t h v S[i:k-1]=t_1t_2...t_hv S[i:k?1]=t1?t2?...th?v是沒有固定的分解,滿足 t 1 t_1 t1?是 lyndon \text{lyndon} lyndon串, t 1 = t 2 = . . . = t h t_1=t_2=...=t_h t1?=t2?=...=th?, v v v是 t h t_h th?的(可為空的)真前綴,令 j = k ? ∣ t 1 ∣ j=k-|t_1| j=k?∣t1?∣。
復雜度為 O ( n ) O(n) O(n)。比sa快啊
代碼
Part 2
lyndon \text{lyndon} lyndon分解的應用:
1.3 1.3 1.3 給定長為 n n n的字符串 S S S,求出 S S S的最小表示法。
方法:將 S S SS SS lyndon \text{lyndon} lyndon分解,找到分解后最后一個字符串,它的首字符為 S S [ p ] SS[p] SS[p],且 p ∈ [ 0 , ∣ S ∣ ) p\in [0,|S|) p∈[0,∣S∣)。可以證明 S S [ p : p + ∣ S ∣ ? 1 ] SS[p:p+|S|-1] SS[p:p+∣S∣?1]是字典序最小的。(運用第一條引理,轉化為比較在原串中的后綴,即sa)
1.4 1.4 1.4 給定長度為 n n n的字符串 S S S,將 S S S分為最多 k k k個串 c 1 c 2 . . . c k c_1c_2...c_k c1?c2?...ck?,求 max ? c i \max c_i maxci?的最小值。
方法:看到字典序,容易想到 lyndon \text{lyndon} lyndon分解。首先把 S S S lyndon \text{lyndon} lyndon分解成 s 1 , . . . , s g s_1,...,s_g s1?,...,sg?,如果 k ≥ g k\ge g k≥g,那么答案即為 s 1 s_1 s1?;否則,如果 s 1 > s 2 s_1>s_2 s1?>s2?,那么顯然可以分成 s 1 s_1 s1?和剩下的所有串,答案還是 s 1 s_1 s1?。因此,考慮分解成 s 1 m s g s_1^ms_g s1m?sg?的情況,如果 k > m k>m k>m,那么答案還是 s 1 s_1 s1?,如果 k ≤ m k\le m k≤m,那么盡量均分一下即可。
推廣:多次詢問,每次詢問 S S S的一段后綴的答案。
考慮求出原串的sa數組,顯然可以求出第一項以及重復次數(可以用哈希),這樣就做完了。
1.5 1.5 1.5 求 S S S的每個前綴的字典序最小的后綴
首先把 S S S lyndon \text{lyndon} lyndon分解成 s 1 , . . . , s g s_1,...,s_g s1?,...,sg?,顯然 s 1 . . . s k s_1...s_k s1?...sk?的字典序最小的后綴是 s k s_k sk?。但是前綴取到分解出來的 lyndon \text{lyndon} lyndon串半截時,答案可能不一樣。
考慮 duval \text{duval} duval算法求 lyndon \text{lyndon} lyndon分解的過程,分類討論:
- 若 s [ k ] > s [ j ] s[k]>s[j] s[k]>s[j],此時 a n s [ k ] ans[k] ans[k]應該等于 i i i,因為 s [ i : k ] s[i:k] s[i:k]構成一個新的 lyndon \text{lyndon} lyndon串
- 若 s [ k ] = s [ j ] s[k]=s[j] s[k]=s[j],此時 a n s [ k ] = a n s [ j ] + k ? j ans[k]=ans[j]+k-j ans[k]=ans[j]+k?j
- 若 s [ k ] < s [ j ] s[k]<s[j] s[k]<s[j],在 lyndon \text{lyndon} lyndon串開頭時更新
1.6 1.6 1.6 求 S S S的每個前綴的字典序最大的后綴
首先把字符比較反過來,然后要盡量向左取,當 s [ k ] ≤ s [ j ] s[k]\le s[j] s[k]≤s[j]的時候, s [ i : k ] s[i:k] s[i:k]這一段都保持了是一個近似 lyndon \text{lyndon} lyndon串,所以都取近似 lyndon \text{lyndon} lyndon串的左端點 i i i作為答案即可。
ps:感覺這個算法就只能考論文題。。。太惡心了。。。