Lyndon Word
定義
對於字符串 \(S\),若 \(S\) 的最小后綴為其本身,那么稱 \(S\) 為 \(\text{Lyndon}\) 串(\(\text{Lyndon Word}\))
即
性質
\(Border(S)=\varnothing\)
推論
如果 \(u,v \in L, u \prec v\Rightarrow uv \in L\)。
\(\mathcal{Proof.}\)
\(1) s=u'v,u\triangleleft u' \Rightarrow uv < u'v\)
\(2) \text{to prove uv<v}\)
\(2.1) u \triangleleft v \Rightarrow uv<v\)
\(2.2) u \sqsubseteq v \Rightarrow v=uv',v<v' \Leftrightarrow uv<uv' \Leftrightarrow uv<v\)
\(3) S=v',uv<v<v'\)
\(Q.E.D.\)
PS: \(\triangleleft\):嚴格小於,且不是前綴,必有一個字母不同,\(\sqsubseteq\):前綴
\(ex.\) 如果 \(u,v\in L,u<v \Rightarrow u^av^b\in L\)
顯然。
Lyndon 分解 (Lyndon Factorization)
任意字符串 \(s\) 可以分解為 \(s=s_1s_2s_3\dots s_k\),其中 \(s_i\) 是 \(\text{Lyndon}\) 串,\(s_i \ge s_{i+1}\),且這種分解方法是唯一的。
\(\mathcal{Proof.}\)
先證存在性:
初始時每段一個字符,然后不斷地將相鄰兩段 \(s_i<s_{i+1}\) 合並。
再證唯一性:
若有兩種方案,取第一次不同的位置,設 \(|s_i| > |s_i'|\),令 \(s_i=s_i's_{i+1}' \dots s_k'pre(s_{k+1}',l)\),則
\[s_i<pre(s_{k+1}',l)\le s_{k+1}' \le s_i' < s_i,矛盾 \]
性質
- \(s_k\) 是最長的 \(\text{Lyndon suffix}\)
- \(s_1\) 是最長的 \(\text{Lyndon prefix}\)
- \(s_k=minsuf(s)\)
\(\mathcal{Proof.}\)
畫圖比划一下,容易(是真的)證得。
Duval 算法
\(\text{Duval}\) 算法可以 \(O(n)\) 時間 \(O(1)\) 額外空間內求出 \(s[1\dots n]\) 的 \(\text{Lyndon}\) 分解。
即
\(\mathcal{Lemma.}\)
若字符串 \(v\) 和字符 \(c\) 滿足 \(vc\) 是某個 \(\text{Lyndon}\) 串的前綴,則對於字符 \(d>c\) 有 \(vd\) 是\(\text{Lyndon}\) 串。
也就是說,如果 \(uav \in L\),那么對於 \((uav)^kua'\):
-
如果 \(a<a'\),那么 \((uav)^kua' \in L\)
-
如果 \(a>a'\),那么 \(\forall w,(uav)^kua'w \notin L\)
\(\Rightarrow CFL[(uav)^kua'w]=(uav)^kCFL(ua'w)\)
因此,我們考慮下面這個算法過程:
用三個循環變量 \(i,j,k\) 維持一個循環不變式:
- \(s[1 \dots i-1] = s_1 s_2 \cdots s_g\) 是已經固定下來的分解,滿足 \(s_l\) 是 \(\text{Lyndon}\) 串,且 \(s_l \le s_{l+1}\)。
- \(j-i\) 是當前最長的 \(\text{Lyndon prefix}\) 的長度,即 \(s[j]\) 是 \(s[k]\) 在 \(\text{Lyndon Prefix}\) 中對應位置的字符。
- \(k\) 是當前讀入的字符的位置。
然后對於當前讀入的字符 \(a\)
- 若 \(a>s[j]\),則令直接令 \(s[i\dots k]\) 成為新的 \(\text{Lyndon Prefix}\)
- 若 \(a=s[j]\),無法切割出新的划分,繼續讀入
- 若 \(a<s[j]\),則遞歸求解,先分解完 \(s[i\dots t]\) ,即 \((uav)^k\),然后將指針指向 \(t+1\) 重新進行算法過程。
Code
int i, j, k;
for (i = 1; i <= N; ) {
for (k = i, j = k + 1; j <= N && s[j] >= s[k]; ++j) {
if (s[j] > s[k]) k = i;
else ++k;
}
while (i <= k) { lyndon[++cnt] = i + j - k - 1; i += j - k; }
}
"Runs" Theorem
先丟一個論文鏈接:The" Runs" Theorem
Lyndon Array
再說。
[ZJOI2017] 字符串
Description
維護一個動態字符串 \(s[1\dots n]\),字符串的字符集是所有 \(|x|\le 10^9\) 的整數。要求支持兩個操作:
- 輸入 \(l,r,d\),對於所有 \(l\le i \le r\),將 \(s[i]\) 修改為 \(s[i]+d\),注意 \(d\) 可能是負數。
- 輸入 \(l,r\),輸出子串 s\([l\dots r]\) 的字典序最小的后綴的起點位置。即,如果最小后綴是 \(s[p\dots r],(l\le p\le r)\),請輸出 \(p\)。