lyndon word学习笔记

似乎是一个很冷门的东西,但是还是有点小用处的
于是花了一个下午学习了一下
你为什么要学什么久啊。。

定义

一个串 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} pipi+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,i1]都已经划分好了
然后,我们对于 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 kj,然后从 i i i开始有若干个循环节
把这些循环节的开头全部弄出来,直到 i > j i>j i>j为止
那么,我们就会得到一个新的 i i i,且 [ 1 , i − 1 ] [1,i-1] [1,i1]都划分好了
并且一定满足递减的条件
至于时间复杂度,可以发现,一个位置最多只会被经过三次,因此是 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直接做就可以了

别的题以后做了再更吧

你可能感兴趣的:(高二生活)