1. 程式人生 > 實用技巧 >Lyndon 分解

Lyndon 分解

Lyndon 串

其嚴格最小字尾為其本身的串,稱為 \(Lyndon\) 串,也就是 \(s\) 是其所有迴圈移位中嚴格最小的。

\(s,t\) 都為 \(Lyndon\) 串是,且 \(s<t\),則 \(st\) 也為 \(Lyndon\) 串。證明 \(t>st\) 後即可證明該性質。

Lyndon 分解

\(Lyndon\) 分解為將 \(s\) 分解得 \(s=s_1s_2s_3 \dots s_k\),且 \(s_i \geqslant s_{i+1}\)\(Lyndon\) 分解是存在且唯一的。

存在性由 \(Lyndon\) 串的性質不難得到,唯一性可以用反證法來證明。

Duval 演算法

\(Duval\) 演算法可以 \(O(n)\) 求出一個串的 \(Lyndon\) 分解。

對於字串 \(s\) 和字元 \(c\),若 \(sc\) 是某個 \(Lyndon\) 串的字首,則對於字元 \(d>c\)\(sd\)\(Lyndon\) 串。

維護三個指標 \(p,i,j\)\([1,p-1]\) 是已經進行完 \(Lyndon\) 分解的部分,\([p,j-1]\)\(s_1s_2s_3 \dots s_kt\),其中 \(t\) 可以為空串,且 \(s_1\)\(Lyndon\) 串和 \(s_1=s_2= \dots =s_k\)

\(t\)\(s_1\) 的字首,滿足 \(s[p,j-1]\) 比上一個分解出的串小。

當前加入字元 \(s_j\),令 \(i=j-|s_1|\),即為 \(t\) 在迴圈串對應的位置。進行分類討論:

\(s_i=s_j\) 時,\(t\) 能繼續匹配,讓 \(i,j\) 都向後移動一個位置。

\(s_i<s_j\) 時,得 \(s[p,j]\)\(Lyndon\) 串,將 \(i\) 移動到 \(p\)\(j\) 向後移動一個位置。

\(s_i>s_j\) 時,得 \(s_1s_2s_3 \dots s_k\) 為分解後的串,然後繼續考慮 \(t\)

\(j\) 向後移動一個位置。

因為 \(p\) 只向後移動,\(j\) 向前移動的距離不超過 \(p\) 向後移動的距離,所以複雜度為 \(O(n)\)

while(p<=n)
{
    int i=p,j=p+1;
    while(j<=n&&s[i]<=s[j]) i=s[i]==s[j++]?i+1:p;
    while(p<=i) p+=j-i,ans^=p-1;
}

這段程式碼求的是 \(Lyndon\) 分解所有右端點的異或和。

應用

求解最小迴圈表示,\(O(n)\) 對所有 \(s[1,i]\) 求最小最大字尾。