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|\):
-
当 \(S_k=S_j\) 时:直接将 \(S_k\) 加入 \(s_2\) 中,性质不发生变化。
-
当 \(S_k<S_j\) 时:直接将 \(t^h\) 的分解方式确定下来,从 \(v\) 的开头重新进行上述流程。
-
当 \(S_k>S_j\) 时,\(v+S_k\) 会得到新的 Lyndon 串,根据之前的 Lyndon 分解的构造方法,这个 Lyndon 串会不断向前合并,最终 \(t^h+v+S_k\) 得到新的 Lyndon 串,成为新的 \(s_2\)。
据此就得到了 \(\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