【学习笔记】Lyndon Word
定义
若一个字符串的最小后缀是它自己,我们称其为串。
等价定义:若是其所有循环重构串中字典序最小的串,则是串。
分解
任意字符串,都可以唯一分解成,其中为串,且
存在性证明
先来看一个引理:
引理1:
如果,都是串,并且字典序,则也是串。
(感觉比较显然吧,但还是证明一下
1.时
因为,所以>,又因为是串,所以的所有非自己的后缀都大于,所以开头在的部分的后缀都大于。因为也是串,所以的所有后缀都大于,的开头在部分的后缀也就大于(在部分的比较就已经大于)
2.时
若不是的前缀,那么在之前就有,所以,同上可证。
若是是的前缀,那么,同上可证。
有了引理之后再来证明。
首先,中的每一个单个字符都是一个串,初始时每段都只有一个字符。
从左往右开始合并,左边已经合并了的字符串大于当前字符的话就把并入,根据引理1可得这样合并后分出来的每一段都是串。
而每次比较的时候都并进去了,所以没有并进去的话,就满足每一段
唯一性证明
(其实这个也比较显然吧,根据上面我们是能并就并了,没有其他可操作的空间,所以就只有一种
这个我们用反证法。
假设对于一个字符串有两种分解
我们记第一次不同的位置为,设
设
指第段串中的前缀
可以得到以下关系:
:是串,所以它的后缀大于它
:一个字符串的前缀小于等于它自己
:分解中,前面的段的字典序大于后面的段的字典序。
:是的前缀,一个字符串的前缀小于等于它自己
综合上述不等式,可以得到,产生矛盾,所以假设不成立
算法
是一种在时间复杂度之内求出一个串的分解的算法。
引理2:
若字符串和字符满足是某个串的前缀,则对于字符有是串。
(觉得还是可以感性理解
证明:
设串为
根据串的性质可得,.
根据的取值范围,长度最大是,那么的长度小于等于。
所以要么是的前缀(在的部分大于),要么大于,总之不可能小于,否则是不会成立的。
所以可以得到:
那么:,所以
算法流程
在这个算法中,我们维护三个变量
其中,是已经固定下来的分解,满足每一段
是没有固定的分解,并且是串,是的一个前缀(可为空)。
,当前扫到未处理的字符是
分三类情况讨论:
:继续往前扫,保持周期
:根据引理2,我们将合并起来,是一个串(是向前合并,和合并起来,再将与前面的合并(注意相等的两个串并不能用引理1进行合并,因为的后缀不大于)。
这里的合并是相当于把当成一个新的,不是就把它当成分解里的一段了,它还有可能和后面的串拼在一起形成一个新的
:的分解被固定为个串,算法从的开头重新开始。
复杂度分析
只会往右移,移动的距离不超过右移的距离(移动,而移动)
复杂度为
Code View
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define N 5000005
#define INF 0x3f3f3f3f
#define LL long long
int rd()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
return f*x;
}
int n,ans;
char s[N];
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++;
}
while(i<=j)
{
ans=ans^(i+k-j-1);
i+=k-j;
}
}
printf("%d\n",ans);
return 0;
}
——注:博客参考了金策的字符串算法选讲内容
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现