Lyndon 串:(s) 的字典序严格小于 (s) 的所有后缀的字典序。
性质:Lyndon 串是它的所有循环同构中最小的一个。
近似 Lyndon 串:若 (s) 为 Lyndon 串,则 (xx....xx') 是近似 Lyndon 串,其中 (x') 是 (x) 的前缀。
Lyndon 分解:将一个串 (S) 分解为 (s_1s_2...s_k),每一个串都是 Lyndon 串,且 (s_i ge s_{i+1})。
性质:Lyndon 分解是唯一的。对于两个 Lyndon 串 (s,t),如果 (s<t),则 (st) 是 Lyndon 串。
用后缀数组求解 Lyndon 分解
每次找 (S) 最小的后缀 (S[i:]),则在 (S[:i]) 的 Lyndon 分解后面加上一项 (S[i:]) 就是答案。
设原字符串为 (S) ,逐个加入字符,我们需要维护扫描的左端点 (l),右端点 (r) 和当前区间 ([l,r]) 的 Lyndon 周期 (d)。
当 (s[r]<s[r-d]) 时,当前的近似 Lyndon 串即将结束,我们需要把它开头的那些完整的 Lyndon 串切下来,并且把最后剩余的一段重新处理,即令 (r=l+1,d=1)。
当 (s[r]>s[r-d]) 时,当前近似 Lyndon 串成为一个 Lyndon 串(它的 Lyndon 周期增大了),故 (d=r-l+1)。
当 (s[r]=s[r-d]) 时,新字符只是当前近似 Lyndon 串的延伸。
#include <bits/stdc++.h>
using namespace std;
string s;
signed main()
{
cin>>s;
int l=0,r=1,d=1;
s+=' ';
while(s[l])
{
if(s[r]<s[r-d])
{
while(l+d<=r) l+=d, cout<<l<<" ";
r=l,d=1;
}
else if(s[r]>s[r-d])
{
d=r-l+1;
}
++r;
}
}