字符串--Lyndon分解

1.定义

一个字符串是 L y n d o n W o r d Lyndon Word LyndonWord,当前仅当这个字符串是其所有后缀中字典序最小的。
一个字符串 s s s L y n d o n Lyndon Lyndon分解是将字符串划分为若干个部分 s 1 s 2 . . . s m s_1s_2...s_m s1s2...sm使得 ∀ 1 < = i < = m : s i \forall 1<=i<=m:s_i 1<=i<=m:si是一个 L y n d o n W o r d Lyndon Word LyndonWord ∀ 1 < = i < m : s i > = s i + 1 \forall 1<=i<m:s_i>=s_{i+1} 1<=i<m:si>=si+1

2.引理

1.如果串 u u u L y n d o n Lyndon Lyndon,串 v v v L y n d o n Lyndon Lyndon串,且 u < v u<v u<v,那么 u + v u+v u+v L y n d o n Lyndon Lyndon串。
证:让 x s u f x_{suf} xsuf表示串 x x x的所有后缀, ∵ v \because v v L y n d o n Lyndon Lyndon串, ∴ v < = v s u f \therefore v<=v_{suf} v<=vsuf,则 u < v < = v s u f u<v<=v_{suf} u<v<=vsuf,又 u < = u s u f u<=u_{suf} u<=usuf u + v < = u s u f + v u+v<=u_{suf}+v u+v<=usuf+v,由定义,结论成立。
推论:若一个 L y n d o n Lyndon Lyndon u v uv uv能分解成两个 L y n d o n Lyndon Lyndon u , v u,v u,v,必有 u < v u<v u<v

2.如果串 u c 1 uc_1 uc1是某个 L y n d o n Lyndon Lyndon串的前缀,字符 c 1 , c 2 c_1,c_2 c1,c2满足 c 2 > c 1 c_2>c_1 c2>c1,那么 u c 2 uc_2 uc2是一个 L y n d o n Lyndon Lyndon串。
证: ∵ u c 1 \because uc_1 uc1是某个 L y n d o n Lyndon Lyndon串的前缀, ∴ u c 1 < = ( u c 1 ) s u f < = ( u c 2 ) s u f \therefore uc_1<=(uc_1)_{suf}<=(uc_2)_{suf} uc1<=(uc1)suf<=(uc2)suf,由定义结论成立(事实上某个 L y n d o n Lyndon Lyndon串的前缀也是一个 L y n d o n Lyndon Lyndon串)。

3.一个字符串的 L y n d o n Lyndon Lyndon分解存在且唯一。
证:初始令 m = ∣ s ∣ m=|s| m=s,重复选择一个 i < m i<m i<m使得 s i < s i + 1 s_i<s_{i+1} si<si+1并将 s i s_i si s i + 1 s_{i+1} si+1合并,直到不存在关系 s i < s i + 1 s_i<s_{i+1} si<si+1,显然 L y n d o n Lyndon Lyndon分解存在。又假设 L y n d o n Lyndon Lyndon s i − 1 < s i < s i + 1 s_{i-1}<s_i<s_{i+1} si1<si<si+1,有 s i − 1 < s i s i + 1 , s i − 1 s i < s i + 1 s_{i-1}<s_is_{i+1},s_{i-1}s_i<s_{i+1} si1<sisi+1si1si<si+1,由传递性得上述形式与合并顺序无关,故分解形式唯一。

3.算法

设前 i − 1 i-1 i1个字符的分解已经固定,现从第 i i i个位置寻找一个新的分解。将新的串分为两个部分 v h + x ( h > = 1 , v h v^h+x(h>=1,v^h vh+x(h>=1,vh表示 v v v重复 h h h ) ) ),其中 v v v是从第 i i i个位置开始一个未固定的分解, x x x v v v的可以非空前缀。现在加入一个新的字符 s k s_k sk,如图所示,其中 ∣ v ∣ = k − j |v|=k-j v=kj
在这里插入图片描述
分三种情况讨论:
1. s j = = s k s_j==s_k sj==sk,让 j = j + 1 , k = k + 1 j=j+1,k=k+1 j=j+1,k=k+1,继续重复算法。
2. s j < s k s_j<s_k sj<sk,由引理 2 2 2 v h + x + s k v^h+x+s_k vh+x+sk是一个 L y n d o n Lyndon Lyndon串,让 j = i j=i j=i继续算法。
3. s j > s k s_j>s_k sj>sk v h v^h vh被固定为 h h h个分解,算法从 x x x的开头重新开始。

算法的指针最多移动 n n n次,时间复杂度为 O ( n ) O(n) O(n)

4.代码

P6114 【模板】Lyndon 分解

#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5;
char s[N];
int n,ans;
int main()
{
	scanf("%s",s+1);
	n=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++;
        }
        //维护的是一个长度为k-j的循环串v
        while(i<=j)
        {
            ans^=i+k-j-1;
            i+=k-j;
        }
    }
	printf("%d\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值