Lyndon 分解

Lyndon 分解

以下所有字符串的大小关系都是对字符串字典序的比较。

定义串 S 为 Lyndon 串当且仅当 S 小于其所有不为 S 的后缀。

该命题等架于 S 是它的所有循环表示中最小的。

定义串 S 的 Lyndon 分解为将 S 分为若干部分 S=w1w2wm 使得 wi 为 Lyndon 串且 w1w2wm

可以证明任何串 S 的 Lyndon 分解存在且唯一。


证明这一点需要一个引理:

引理 1:若串 u,v 为 Lydnon 串且 u<v,则 uv 也为 Lyndon 串。

证明:

|u|>|v|:则 v>uv,那么 v 的后缀依然 >uv,得证。

|u||v|:若 u 不为 v 的前缀则 v>uv 得证。否则,设 v=ut,有 t<v,与 v 是 Lyndon 串矛盾

Lyndon 分解的存在性证明:

根据引理,不难得到一个 Lydnon 分解的构造方案:

初始令 m=|S|,wi=Si,显然这满足 wi 为 Lyndon 串的条件。接下来不断找到 wi<wi+1 的位置,将 wi,wi+1 合并到一起,得到的串依然是 Lyndon 串。

Lyndon 分解的唯一性证明:

S 存在两个 Lyndon 分解:

S=a1a2am1=b1b2bm2

找到最小的 i 使得 aibi,不妨设 |ai|>|bi|,设 ai=bibi+1pre(bk,l),则有 ai<pre(bk,l)bkbiai,矛盾。


在讨论 Lyndon 分解的 O(n) 构造前,再给出引理:

引理 2:若字符串 v 与字符 c,满足 vc 是 Lyndon 串的前缀,则对于字符 d>cvd 是 Lyndon 串。

证明:

vct 为 Lyndon 串。则 i[2,|v|]suf(v,i)ct>vct,故 suf(v,i)cvsuf(v,i)d>v,同时又有 d>cv,故得证。

Duval 算法

算法的每一时刻都将串 S 分为三个部分 s1s2s3,其中 s1 是已经确定的分解,s3 是未分解的部分,s2 是正在分解的部分,且 s2=th+v,其中 vt 的一个前缀,t 是一个 Lyndon 串。

每一步将 s3 的第一个字母 Sk 加入 s2 中,记 j=k|t|

  • Sk=Sj 时:直接将 Sk 加入 s2 中,性质不发生变化。

  • Sk<Sj 时:直接将 th 的分解方式确定下来,从 v 的开头重新进行上述流程。

  • Sk>Sj 时,v+Sk 会得到新的 Lyndon 串,根据之前的 Lyndon 分解的构造方法,这个 Lyndon 串会不断向前合并,最终 th+v+Sk 得到新的 Lyndon 串,成为新的 s2

据此就得到了 O(n) 求解 Lyndon 分解的方法。

洛谷模板题 P6114 代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
char s[N]; 
int n,ans;
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	int i=1,j,k;
	while(i<=n){
		j=i,k=i+1;
		for(;k<=n&&s[k]>=s[j];++k)
			j=s[k]>s[j]?i:j+1;
		while(i<=j) ans^=i+k-j-1,i+=k-j;
	}
	printf("%d\n",ans);
	return 0;
} 
posted @   cjTQX  阅读(104)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2021-06-11 "Orz Panda" Cup F.Flow of Orz Pandas
点击右上角即可分享
微信分享提示