Lyndon分解
我们定义一个字符串是
首先很显然的是,若
引理1:如果
我们设
由于
定义一个串
,满足 是 串。
存在性证明
起初我们可以将
唯一性证明
假设对于
我们设
那么
由
引理2:若字符串
设这个
那么可得:
所以
又因为
性质1:若字符串
证明:假设
性质2:如果
证明:这个就是反过来的引理1,因为
性质3:如果
首先我们介绍另外一个概念:如果一个字符串
整体描述一下,该算法每一次尝试将
我们来更详细地解释一下算法的过程。定义一个指针
- 如果
,则将 添加到 末尾不会影响它的近似简单性。于是我们只需要让指针 自增(移向下一位)即可。 - 如果
,那么 就变成了一个 串,于是我们将指针 自增,而让 指向 的首字符,这样 就变成了一个循环次数为 的新 串了。 - 如果
,则 就不是一个近似简单串了,那么我们就要把 分解出它的一个 子串,这个 子串的长度将是 ,即它的一个循环节。然后把 变成分解完以后剩下的部分,继续循环下去(注意,这个情况下我们没有改变指针 ),直到循环节被截完。对于剩余部分,我们只需要将进度“回退”到剩余部分的开头即可。
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
using namespace std;
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
int n,ans;
char s[5000005];
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^=i+k-j-1;
i+=k-j;
}
}write(ans),pc('\n');
return 0;
}
这玩意根本不会考到好吧(
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现