Lyndon分解和最小循环表示学习
Posted nealchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lyndon分解和最小循环表示学习相关的知识,希望对你有一定的参考价值。
做CF594E涉及的两个知识点。以下字符串采用Python记法。
Lyndon分解
定义 $S$ 是Lyndon串,当且仅当对于任意有意义的正整数 $i$ 有 $S<S[i:]$.
定义 $S$ 的Lyndon分解是一个Lyndon串的序列 $s_1, s_2, ldots, s_n$, 使得 $S=s_1s_2 cdots s_n$ 并且 $s_1 ge s_2 ge cdots ge s_n$.
Lyndon分解存在且唯一。
不难发现,Lyndon分解可以这么得到:对于 $S$, 取最小的后缀 $S[i:]$, $S$ 的Lyndon分解,是在 $S[:i]$ 的Lyndon分解的最后加上一项 $S[i:]$ 得到的序列。
于是,Lyndon分解可以用后缀数组求,但是这样太复杂了。
Lyndon分解的Duval算法:
设原字符串为 $S$. 逐个加入字符,设已能确定 $S[:i]$ 的Lyndon分解 $s_1, s_2, ldots, s_n$ 为 $S$ 的Lyndon分解的前缀,再尽可能地扩充字符串 $S[i:k]$, 使得 $S[i:k]$ 具有Lyndon周期 $t$, 也就是说,$S[i:k]=(n imes t)u$, 其中 $u$ 是 $t$ 的(可以为空的)前缀,且 $t$ 是Lyndon串。考虑加入字符 $S_k$, 若 $k=|S|$ 则令 $S_k=-infty$.
- 若 $S_k<S_{k-|t|}$, 则 $S[i:k+1]$ 就没有Lyndon周期了。不过此时 $S[:i+n|t|]$ 的Lyndon分解已确定,即在 $S[:i]$ 的基础上加入 $n$ 个 $t$, 取新参数 $i‘=i+n|t|, k‘=i‘+1$ 重来。
- 若 $S_k=S_{k-|t|}$, 则 $t$ 也是 $S[i:k+1]$ 的Lyndon周期。
- 若 $S_k>S_{k-|t|}$, 则 $S[i:k+1]$ 的Lyndon周期是其本身。
实现上我们只需要维护 $i, k$ 以及 $j=k-|t|$. 代码链接
扩充 $S[i:k]$ 的过程中 $i+kle2|S|$ 且随扩充总轮数递增,因此该算法时间 $O(|S|)$, 除去输入输出只需要 $O(1)$ 额外空间,是一个非常简短而高效的算法。
最小循环表示
最小循环表示,也就是对于字符串 $S$, 求出最小的 $S_i=S[i:]S[:i]$.
我们维护两个决策 $i, j$, 满足 $i<j$ 并且 $[0, i)$ 和 $(i, j)$ 中的整数都不是最优决策。
初始时,设 $i=0, j=1$.
我们通过枚举比较求出 $S_i$ 和 $S_j$ 的最长公共前缀 $k$.
- 若 $S_i=S_j$, $S_i$ 即为最优解。这是因为,字符串以 $j-i$ 为循环节循环,而 $(i, j)$ 中任何整数都不是最优决策。
- 若 $S_i<S_j$, 说明 $[j, j+k]$ 内的整数不是最小循环表示,因为它总比 $[i, i+k]$ 内的对应决策劣,因此令 $j gets j+k+1$. 此时上述性质未改变。
- 若 $S_i>S_j$, 同理令 $i gets i+k+1$, 若 $i ge j$ 则令 $j gets i+1$, 上述性质仍未改变。
1 int n=strlen(s), cho=0; 2 for(int i=1, j=0; cho<l&&i<l&&j<l; ) { 3 int t=s[(cho+j)%l]-s[(i+j)%l]; 4 if(t==0) ++j; else (t<0?i:cho)+=j+1, j=0; 5 if(cho>=i) i=cho+1; 6 }
以上是关于Lyndon分解和最小循环表示学习的主要内容,如果未能解决你的问题,请参考以下文章