Lyndon分解

定义:

Lyndon串:\(S_{1...|S|}\)的所有后缀中,\(S_{1...n}\)是一个最小的后缀,则称\(S\)为一个Lyndon串

Lyndon分解:将一个字符串\(S\)分解为 \(s_1+s_2+...+s_k , 且s_1 >= s_2>=...>=s_k\) , \(\{s_i\}为Lyndon串\)


性质:

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

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

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

Duval 方法:

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

流程:

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

假定\(S[:i-1]\)的字符串已经被分解完成

初始化\(j = i , k = i + 1\)

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

\(S_j == S_k\) 😒 j,k$同时延伸就好了

\(S_j < S_k\)的时候,因为需要满足Lyndon性质,\(T_{last - 1} < T_{last}\)不满足了

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

合法性: 考虑此时 \(v + s[k]一定也为一个Lyndon , 且T < v + s[k] , 故T^h + v + s[k]\)也应当为一个Lyndon

\(S_j > S_k\)的时候,此时这 若干个\(T^h\)已经是\(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 @ 2022-03-16 19:49  After_rain  阅读(198)  评论(0)    收藏  举报