1.定义
一个字符串是
L
y
n
d
o
n
W
o
r
d
Lyndon Word
LyndonWord,当前仅当这个字符串是其所有后缀中字典序最小的。
一个字符串
s
s
s的
L
y
n
d
o
n
Lyndon
Lyndon分解是将字符串划分为若干个部分
s
1
s
2
.
.
.
s
m
s_1s_2...s_m
s1s2...sm使得
∀
1
<
=
i
<
=
m
:
s
i
\forall 1<=i<=m:s_i
∀1<=i<=m:si是一个
L
y
n
d
o
n
W
o
r
d
Lyndon Word
LyndonWord,
∀
1
<
=
i
<
m
:
s
i
>
=
s
i
+
1
\forall 1<=i<m:s_i>=s_{i+1}
∀1<=i<m:si>=si+1。
2.引理
1.如果串
u
u
u是
L
y
n
d
o
n
Lyndon
Lyndon,串
v
v
v是
L
y
n
d
o
n
Lyndon
Lyndon串,且
u
<
v
u<v
u<v,那么
u
+
v
u+v
u+v是
L
y
n
d
o
n
Lyndon
Lyndon串。
证:让
x
s
u
f
x_{suf}
xsuf表示串
x
x
x的所有后缀,
∵
v
\because v
∵v是
L
y
n
d
o
n
Lyndon
Lyndon串,
∴
v
<
=
v
s
u
f
\therefore v<=v_{suf}
∴v<=vsuf,则
u
<
v
<
=
v
s
u
f
u<v<=v_{suf}
u<v<=vsuf,又
u
<
=
u
s
u
f
u<=u_{suf}
u<=usuf,
u
+
v
<
=
u
s
u
f
+
v
u+v<=u_{suf}+v
u+v<=usuf+v,由定义,结论成立。
推论:若一个
L
y
n
d
o
n
Lyndon
Lyndon串
u
v
uv
uv能分解成两个
L
y
n
d
o
n
Lyndon
Lyndon串
u
,
v
u,v
u,v,必有
u
<
v
u<v
u<v。
2.如果串
u
c
1
uc_1
uc1是某个
L
y
n
d
o
n
Lyndon
Lyndon串的前缀,字符
c
1
,
c
2
c_1,c_2
c1,c2满足
c
2
>
c
1
c_2>c_1
c2>c1,那么
u
c
2
uc_2
uc2是一个
L
y
n
d
o
n
Lyndon
Lyndon串。
证:
∵
u
c
1
\because uc_1
∵uc1是某个
L
y
n
d
o
n
Lyndon
Lyndon串的前缀,
∴
u
c
1
<
=
(
u
c
1
)
s
u
f
<
=
(
u
c
2
)
s
u
f
\therefore uc_1<=(uc_1)_{suf}<=(uc_2)_{suf}
∴uc1<=(uc1)suf<=(uc2)suf,由定义结论成立(事实上某个
L
y
n
d
o
n
Lyndon
Lyndon串的前缀也是一个
L
y
n
d
o
n
Lyndon
Lyndon串)。
3.一个字符串的
L
y
n
d
o
n
Lyndon
Lyndon分解存在且唯一。
证:初始令
m
=
∣
s
∣
m=|s|
m=∣s∣,重复选择一个
i
<
m
i<m
i<m使得
s
i
<
s
i
+
1
s_i<s_{i+1}
si<si+1并将
s
i
s_i
si和
s
i
+
1
s_{i+1}
si+1合并,直到不存在关系
s
i
<
s
i
+
1
s_i<s_{i+1}
si<si+1,显然
L
y
n
d
o
n
Lyndon
Lyndon分解存在。又假设
L
y
n
d
o
n
Lyndon
Lyndon串
s
i
−
1
<
s
i
<
s
i
+
1
s_{i-1}<s_i<s_{i+1}
si−1<si<si+1,有
s
i
−
1
<
s
i
s
i
+
1
,
s
i
−
1
s
i
<
s
i
+
1
s_{i-1}<s_is_{i+1},s_{i-1}s_i<s_{i+1}
si−1<sisi+1,si−1si<si+1,由传递性得上述形式与合并顺序无关,故分解形式唯一。
3.算法
设前
i
−
1
i-1
i−1个字符的分解已经固定,现从第
i
i
i个位置寻找一个新的分解。将新的串分为两个部分
v
h
+
x
(
h
>
=
1
,
v
h
v^h+x(h>=1,v^h
vh+x(h>=1,vh表示
v
v
v重复
h
h
h次
)
)
),其中
v
v
v是从第
i
i
i个位置开始一个未固定的分解,
x
x
x是
v
v
v的可以非空前缀。现在加入一个新的字符
s
k
s_k
sk,如图所示,其中
∣
v
∣
=
k
−
j
|v|=k-j
∣v∣=k−j:
分三种情况讨论:
1.
s
j
=
=
s
k
s_j==s_k
sj==sk,让
j
=
j
+
1
,
k
=
k
+
1
j=j+1,k=k+1
j=j+1,k=k+1,继续重复算法。
2.
s
j
<
s
k
s_j<s_k
sj<sk,由引理
2
2
2得
v
h
+
x
+
s
k
v^h+x+s_k
vh+x+sk是一个
L
y
n
d
o
n
Lyndon
Lyndon串,让
j
=
i
j=i
j=i继续算法。
3.
s
j
>
s
k
s_j>s_k
sj>sk,
v
h
v^h
vh被固定为
h
h
h个分解,算法从
x
x
x的开头重新开始。
算法的指针最多移动 n n n次,时间复杂度为 O ( n ) O(n) O(n)。
4.代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5;
char s[N];
int n,ans;
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;)
{
int j=i,k=i+1;
while(k<=n&&s[j]<=s[k])
{
if(s[j]<s[k]) j=i;
else j++;
k++;
}
//维护的是一个长度为k-j的循环串v
while(i<=j)
{
ans^=i+k-j-1;
i+=k-j;
}
}
printf("%d\n",ans);
}