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串\)
- 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;
}

浙公网安备 33010602011771号