似乎是一个很冷门的东西,但是还是有点小用处的
于是花了一个下午学习了一下
你为什么要学什么久啊。。
定义
一个串
S
S
S是
l
y
n
d
o
n
w
o
r
d
lyndon\ word
lyndon word,当且仅当满足整个串是最小的后缀
定义字符串的大小关系就是字典序的大小关系
性质
当
u
u
u,
v
v
v均为
l
y
n
d
o
n
w
o
r
d
lyndon\ word
lyndon word,且
u
u
u<
v
v
v,那么
u
v
uv
uv也是一个
l
y
n
d
o
n
w
o
r
d
lyndon\ word
lyndon word
其中uv就是把两个串拼起来,证明还是比较显然的,这里就不证了
Lyndon 划分
对于一个字符串,如果可以划分为若干个串
S
=
p
1
+
p
2
+
p
3
+
.
.
.
.
.
+
p
n
S=p_1+p_2+p_3+.....+p_n
S=p1+p2+p3+.....+pn
使得每一个
p
p
p都是一个
l
y
n
d
o
n
w
o
r
d
lyndon\ word
lyndon word,并且
p
i
≥
p
i
+
1
p_i\ge p_{i+1}
pi≥pi+1
可以发现,一个字符串,一定存在一种
L
y
n
d
o
n
Lyndon
Lyndon划分
证明可以用构造法来证明
一开始先所有
p
p
p设为单个字母
那么显然,对于第一个条件是满足的
那么只需要满足递减的关系就可以了
可以发现
p
i
<
p
i
+
1
p_i\lt p_{i+1}
pi<pi+1,他合起来也是一个
l
y
n
d
o
n
w
o
r
d
lyndon\ word
lyndon word
并且可以发现,一个串,他的
L
y
n
d
o
n
Lyndon
Lyndon划分是唯一的
构造Lyndon 划分方法1
上一个部分告诉了我们求
L
y
n
d
o
n
Lyndon
Lyndon划分的一个方法
就是维护类似单调栈的东西就可以了
但是,这里涉及到要快速的比两个字符串的大小,似乎除了二分hash没有什么办法
因此复杂度会多一个
l
o
g
log
log,也就是
n
l
o
g
n
nlogn
nlogn
构造Lyndon 划分方法2
可以发现,这个玩意可以用后缀数组来实现
把串反串
把后缀排序,每次取最前的,然后一直取到尾,直到某个元素被取过位置
yy一下不难得到这个做法的正确性
那么复杂度就取决于后缀数组的复杂度了
用倍增算法就是
n
l
o
g
n
nlogn
nlogn的,如果使用dc3,就可以做到
O
(
n
)
O(n)
O(n)了
如果二分hash就是
n
l
o
g
2
nlog^2
nlog2
构造Lyndon 划分方法3
D
u
v
a
l
Duval
Duval算法
是一个专门解决这个问题的方法,时间复杂度也是线性的
就是维护三个指针
i
,
j
,
k
i,j,k
i,j,k
i
i
i表示,我们现在要划分的开头,也就是
[
1
,
i
−
1
]
[1,i-1]
[1,i−1]都已经划分好了
然后,我们对于
p
i
p_i
pi相同的一起构造
至于j和k的具体定义,似乎也不是很好说,那就先看算法过程来感受一下吧
一开始
j
=
i
,
k
=
i
+
1
j=i,k=i+1
j=i,k=i+1,然后开始循环
分三个情况
a
[
k
]
>
a
[
j
]
a[k]>a[j]
a[k]>a[j]那么以当前串一定不可能比原来的小,于是j=i,k++
a
[
k
]
=
a
[
j
]
a[k]=a[j]
a[k]=a[j]那么以当前串可能会小,于是j++,k++
a
[
k
]
<
a
[
j
]
a[k]<a[j]
a[k]<a[j]那么这里一定要断开了,退出循环
可以发现,这里的
p
p
p的长度就是
k
−
j
k-j
k−j,然后从
i
i
i开始有若干个循环节
把这些循环节的开头全部弄出来,直到
i
>
j
i>j
i>j为止
那么,我们就会得到一个新的
i
i
i,且
[
1
,
i
−
1
]
[1,i-1]
[1,i−1]都划分好了
并且一定满足递减的条件
至于时间复杂度,可以发现,一个位置最多只会被经过三次,因此是
O
(
n
)
O(n)
O(n)的,常数较小
这个的话yy还是挺好证明的
代码大概是这样的
cnt=0;int u=1,i,j;
while (u<=n)
{
for (i=u,j=i+1;j<=n&&ss[j]>=ss[i];j++)
{
if (ss[j]>ss[i]) i=u;
else i++;
}
while (u<=i) {x[++cnt]=u+(j-i)-1;u=u+(j-i);}
}
例题
https://loj.ac/problem/129
就是一个赤裸裸的模板题,代码已经放到上面了
给你一个串
S
S
S
你可以把他分成若干个串
S
=
p
1
+
p
2
+
.
.
.
.
.
+
p
n
S=p_1+p_2+.....+p_n
S=p1+p2+.....+pn
然后对于每一个
p
p
p,你可以把它翻转也可以不翻转
然后最后再拼起来,要字典序最小
把串反过来
可以发现,其实就是
l
y
n
d
o
n
lyndon
lyndon划分后,不断取后面的
l
y
n
d
o
n
w
o
r
d
lyndon\ word
lyndon word直接做就可以了
别的题以后做了再更吧