题解 P6127 【【模板】Lyndon 分解】
大概是我贡献的第二道模板?
\text{Lyndon} 分解详解
我们定义一个串是
该命题等价于这个串是它的所有循环表示中字典序最小的。
引理 1:如果 u 和 v 都是 \text{Lyndon} 串并且 u<v ,则 uv 也是 \text{Lyndon} 串。
证明:
1、若 \operatorname{len}(u)\ge\operatorname{len}(v)
这时,
2、若 \operatorname{len}(u)<\operatorname{len}(v)
若
若
我们定义一个串
可以证明这种划分存在且唯一。
存在性证明
初始令
唯一性证明
假设对于字符串
不妨设
观察
那么由
矛盾。
引理2:若字符串 v 和字符 c 满足 vc 是某个 \text{Lyndon} 串的前缀,则对于字符 d>c 有 vd 是 \text{Lyndon} 串。
证明:
设该
则
所以
同时因为
故
\text{Duval} 算法
这个算法可以在
该算法中我们仅需维护三个变量
维持一个循环不变式:
-
-
s[i,k-1]=t^h+v(h>1)$ 是没有固定的分解,满足 $t$ 是 $\text{Lyndon}$ 串,且 $v$ 是 $t$ 的可为空的不等于 $t$ 的前缀,且有 $s_g>s[i,k-1]
如下图:
当前读入的字符是
分三种情况讨论:
- 当
s[k]=s[j] 时,直接k\leftarrow k+1,j\leftarrow j+1 ,周期k-j 继续保持 - 当
s[k]>s[j] 时,由引理 2 可知v+s[k] 是\text{Lyndon} 串,由于\text{Lyndon} 分解需要满足s_i\ge s_{i+1} ,所以不断向前合并,最终整个t^h+v+s[k] 形成了一个新的\text{Lyndon} 串。 - 当
s[k]<s[j] 时,t^h 的分解被固定下来,算法从v 的开头处重新开始。
复杂度分析:
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
char s[5000005];
int n,ans;
int main()
{
scanf("%s",s+1);
n=(int)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++;
}
while(i<=j)//从v的开头重新开始
{
ans^=i+k-j-1;
i+=k-j;
}
}
printf("%d\n",ans);
return 0;
}