Lyndon分解
一个似乎比较偏门的知识?
定义
- Lyndon串:若某字符串中所有后缀字典序最小的是这个字符串本身,则这个串为 Lyndon串。
- 近似Lyndon串:设 $t$ 是一个Lyndon串,$t^c$ 为 $t$ 拼接 $c$ 次,$t’$ 为 $t$ 串可空前缀,那么 $t^c+t’$ 为近似Lyndon串。
- Lyndon分解:将一个字符串 $S$ 分解成一个字符串序列 $s_1,s_2\cdots s_m$,其中 $s_i$ 是Lyndon串,$s=s_1+s_2+\cdots+s_m$(+号表示拼接),且 $\forall i\in[1,m),s_i\geq s_{i+1}$。
定理
- 若 $s,t$ 为Lyndon串,且 $s<t$ ,则 $st$ 为Lyndon串。
- 对于一个字符串,Lyndon分解唯一。
第一个定理显然,第二个可以用反证法。
Duval 算法
考虑依次增加一个数。
维护三个指针 $i,j,k$。
表示 $[1,i)$ 的字母都已经在Lyndon分解里面了,现在在考虑 $i$ 及其后面的字母;$[i,k)$ 可以表示为 $t^c+t’$ 的形式(即近似Lyndon串);$j=k-|t|$,即 $k$ 一个周期前的字母。
考虑第 $k$ 个字母。
分三种情况讨论:
- $s_j=s_k$,那么可以继续接上去,$j,k$ 右移一位。
- $s_j<s_k$,那么 $[i,k]=t^c+t’+s_k$ 就是一个新的Lyndon串,此时将 $j$ 设为 $i$,然后 $k$ 右移一位,考虑下一个 $k$。
- $s_j>s_k$,那么只能 $c$ 个 $t$ 串作为新的Lyndon串,然后将 $i$ 设为 $t’$ 的开头,重新开始考虑,即 $j=i,k=i+1$。
时间复杂度 $O(n)$。
程序实现:
1 | int main() |
最小表示法
一个字符串的最小表示为所有循环同构的串中,字典序最小的那个。
可以用Lyndon分解求出。将 $s+s$ 进行Lyndon分解。然后找到分解后Lyndon串首字母位置 $\le n$ 的最大的位置。从那个位置开始的就是最小表示。