Lyndon Word
定义
对于字符串 (S),若 (S) 的最小后缀为其本身,那么称 (S) 为 ( ext{Lyndon}) 串(( ext{Lyndon Word}))
即
性质
(Border(S)=varnothing)
推论
如果 (u,v in L, u prec vRightarrow uv in L)。
(mathcal{Proof.})
(1) s=u'v,u riangleleft u' Rightarrow uv < u'v)
(2) ext{to prove uv<v})
(2.1) u riangleleft 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: ( riangleleft):严格小于,且不是前缀,必有一个字母不同,(sqsubseteq):前缀
(ex.) 如果 (u,vin L,u<v Rightarrow u^av^bin L)
显然。
Lyndon 分解 (Lyndon Factorization)
任意字符串 (s) 可以分解为 (s=s_1s_2s_3dots s_k),其中 (s_i) 是 ( ext{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) 是最长的 ( ext{Lyndon suffix})
- (s_1) 是最长的 ( ext{Lyndon prefix})
- (s_k=minsuf(s))
(mathcal{Proof.})
画图比划一下,容易(是真的)证得。
Duval 算法
( ext{Duval}) 算法可以 (O(n)) 时间 (O(1)) 额外空间内求出 (s[1dots n]) 的 ( ext{Lyndon}) 分解。
即
(mathcal{Lemma.})
若字符串 (v) 和字符 (c) 满足 (vc) 是某个 ( ext{Lyndon}) 串的前缀,则对于字符 (d>c) 有 (vd) 是( ext{Lyndon}) 串。
也就是说,如果 (uav in L),那么对于 ((uav)^kua'):
-
如果 (a<a'),那么 ((uav)^kua' in L)
-
如果 (a>a'),那么 (forall w,(uav)^kua'w otin 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) 是 ( ext{Lyndon}) 串,且 (s_l le s_{l+1})。
- (j-i) 是当前最长的 ( ext{Lyndon prefix}) 的长度,即 (s[j]) 是 (s[k]) 在 ( ext{Lyndon Prefix}) 中对应位置的字符。
- (k) 是当前读入的字符的位置。
然后对于当前读入的字符 (a)
- 若 (a>s[j]),则令直接令 (s[idots k]) 成为新的 ( ext{Lyndon Prefix})
- 若 (a=s[j]),无法切割出新的划分,继续读入
- 若 (a<s[j]),则递归求解,先分解完 (s[idots 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[1dots n]),字符串的字符集是所有 (|x|le 10^9) 的整数。要求支持两个操作:
- 输入 (l,r,d),对于所有 (lle i le r),将 (s[i]) 修改为 (s[i]+d),注意 (d) 可能是负数。
- 输入 (l,r),输出子串 s([ldots r]) 的字典序最小的后缀的起点位置。即,如果最小后缀是 (s[pdots r],(lle ple r)),请输出 (p)。