Lyndon分解

定义:

Lyndon串:S1...|S|的所有后缀中,S1...n是一个最小的后缀,则称S为一个Lyndon串

Lyndon分解:将一个字符串S分解为 s1+s2+...+sk,s1>=s2>=...>=sk , {si}Lyndon


性质:

1.有两个Lyndon串 {u,v|u<v} ,则u+v也为一个Lyndon串

2.若存在字符串v,以及字符c , 满足v+c为某个Lyndon串的前缀,则有 d>c,v+dLyndon

  1. Lyndon分解对于一个串是唯一的

Duval 方法:

一个可以在O(n)/O(1)的时空复杂度里面求出一个串的Lyndon分解

流程:

维护三个指针i,j,k从做向右依次求出Lyndon分解

假定S[:i1]的字符串已经被分解完成

初始化j=i,k=i+1

考虑在以i为起点的串 一直延伸下去满足Sj<=Sk , 并且表示为若干个相同的字符串T以及T的一个真前缀v拼接而成

Sj==Sk 😒 j,k$同时延伸就好了

Sj<Sk的时候,因为需要满足Lyndon性质,Tlast1<Tlast不满足了

于是就把[i,j]重新当成一个Lyndon串

合法性: 考虑此时 v+s[k]LyndonT<v+s[k],Th+v+s[k]也应当为一个Lyndon

Sj>Sk的时候,此时这 若干个Th已经是h段Lyndon串了,直接跳到v即可

代码:

#include<bits/stdc++.h>
#define MAXN 5000005
using namespace std;

int n,ans;
char s[MAXN];

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 = i + k - j;
		}
	}
	cout<<ans<<endl;
}
posted @   After_rain  阅读(174)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示