其他分享
首页 > 其他分享> > Lyndon 分解

Lyndon 分解

作者:互联网

Lyndon 分解

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

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

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

定义串 \(S\) 的 Lyndon 分解为将 \(S\) 分为若干部分 \(S=w_1w_2\dots w_m\) 使得 \(w_i\) 为 Lyndon 串且 \(w_1\ge w_2\ge \dots \ge w_m\)。

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


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

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

证明:

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

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

Lyndon 分解的存在性证明:

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

初始令 \(m=|S|,w_i=S_i\),显然这满足 \(w_i\) 为 Lyndon 串的条件。接下来不断找到 \(w_i<w_{i+1}\) 的位置,将 \(w_i,w_{i+1}\) 合并到一起,得到的串依然是 Lyndon 串。

Lyndon 分解的唯一性证明:

设 \(S\) 存在两个 Lyndon 分解:

\(S=a_1a_2\dots a_{m_1}=b_1b_2\dots b_{m_2}\)。

找到最小的 \(i\) 使得 \(a_i\not= b_i\),不妨设 \(|a_i|>|b_i|\),设 \(a_i=b_ib_{i+1}\dots pre(b_k,l)\),则有 \(a_i<pre(b_k,l)\le b_k\le b_{i}\le a_i\),矛盾。


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

引理 2:若字符串 \(v,c\),满足 \(vc\) 是 Lyndon 串的前缀,则对于 \(d>c\) 有 \(vd\) 是 Lyndon 串。

证明:

设 \(vct\) 为 Lyndon 串。则 \(\forall i\in[2,|v|]\),\(suf(v,i)ct>vct\),故 \(suf(v,i)c\ge v\),\(suf(v,i)d>v\),同时又有 \(d>c\ge v\),故得证。

Duval 算法

算法的每一时刻都将串 \(S\) 分为三个部分 \(s_1s_2s_3\),其中 \(s_1\) 是已经确定的分解,\(s_3\) 是未分解的部分,\(s_2\) 是正在分解的部分,且 \(s_2=t^h+v\),其中 \(v\) 是 \(t\) 的一个前缀,\(t\) 是一个 Lyndon 串。

每一步将 \(s_3\) 的第一个字母 \(S_k\) 加入 \(s_2\) 中,记 \(j=k-|t|\):

据此就得到了 \(\mathcal 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;
} 

标签:dots,int,Lyndon,ge,分解,引理
来源: https://www.cnblogs.com/tqxboomzero/p/16366998.html