Lyndon分解学习笔记
# Lyndon 串 (Lyndon word)
一个串是 Lyndon 串,当且仅当这个串的最小后缀就是这个串本身。
在 Wiki 上还有另外一个等价的定义:串是其所有循坏位移中最小的一个。(见Wiki (opens new window))
# Lyndon 分解
将字符串分解成,使得所有都为 Lyndon word
,且。
注意:在本文中,所有对字符串进行的+
操作均代表连接两个字符串
# 引理1. 若都是Lyndon串且,则也是Lyndon串
若
显然,因此。
若
- 为的前缀时,若,则有,矛盾
- 不为的前缀时,显然
易得。
由于,且为Lyndon串,因此的所有后缀都大于。
# 引理2. Lyndon分解存在且唯一
初始令 并且 然后每次不断找到 并且合并为一个串(由引理1可知,合并后的串为仍为Lyndon串)。最后一定能使得所有的 。
存在性得证。
假设存在两个Lyndon分解,分别为
不妨令,则,且
由Lyndon性质可知:
又因为为的前缀,因此
根据划分,可知
最终得到“不等式”:,“不等式”矛盾。
唯一性得证。
# 引理3. 若串与字符满足是某个Lyndon串的前缀,则对于字符,是Lyndon串
设该Lyndon串为,则,因此。
又因为,因此。
故为Lyndon串。
# Duval 算法
维护3个指针。
- 为已经固定的(处理好了的)分解。
- 为尚未固定的分解,满足串是Lyndon串,为的可为空的前缀且。
当前读入,令
若,由于为的前缀,根据引理3可知,为Lyndon串。
但此时若单独划分出,并不能满足的划分要求,因此要与前面所有合并。
最终得到新的Lyndon串 。但此时不能确定该串是否为一个独立的划分。
若,可知周期继续,令即可。
若,显然不是Lyndon串,此时前面的分解固定了,算法从的开头继续。
时间复杂度
# 例题: 洛谷 P6114
给定一个串,求其Lyndon划分,并输出一个整数,代表所有右端点(1-indexed)的异或和。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e6 + 1000;
char s[maxn];
int len, ans = 0;
signed main(){
cin >> (s + 1);
len = strlen(s + 1);
int i = 1, j, k;
while(i <= len){
j = i, k = i + 1;
while(k <= len && s[k] >= s[j]){
j = (s[k]==s[j])?j+1:i;
k++;
}
while(i <= j){ // j < 串v开头的位置
ans ^= i + (k - j) - 1;
i += k - j; // k - j: 循环节长度
}
}
cout << ans << '\n';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 参考
上次更新: 2021/02/24, 03:37:30