Minimum Index【Lyndon分解】-2020杭电多校1
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6761
分析:
\(Lyndon\) 分解:
\(Lyndon\) 串:对于字符串 \(s\),如果 \(s\) 的字典序严格小于 \(s\) 的所有后缀的字典序,我们称 \(s\) 是简单串,或者 \(Lyndon\) 串 。
性质:任意字符串 \(s\) 都可以分解为 \(s=s_1s_2…s_k\),其中 \(∀s_i\) 为 \(Lyndon\) 串且 \(s_i⩾s_{i+1}\),且这种分解方法是唯一的。
\(Duval\) 算法:
该算法可以在 \(O(n)\) 的时间内求出串 \(s\) 的 \(Lyndon\) 分解。
模板代码-Lyndon 分解:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = (1 << 21) + 1;
char s[MAXN];
int main() {
scanf("%s", s + 1);
int N = strlen(s + 1), j, k;
for(int i = 1; i <= N;) {
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) {
printf("%d ", i + k - j - 1);
i += k - j;
}
}
return 0;
}
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+6;
const int mod=1e9+7;
int ans[N];
char ss[N];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",ss+1);
int len=strlen(ss+1);
int i=1;
ans[1]=1;
while(i<=len)
{//重新开始分解
int j=i,k=i+1;//i是近似串的开始
while(k<=len&&ss[j]<=ss[k])
{
if(ss[j]<ss[k])//加入到近似的Lyndon串中
{
j=i;
ans[k]=i;
}
else//继续保持
{
ans[k]=ans[j]+k-j;
j++;
}
k++;
}
while(i<=j)//起点向后移
i+=k-j;
ans[k]=i;//
}
ll base=1112,fac=1,res=0;
for(int i=1;i<=len;i++)
{
res=(res+fac*ans[i]%mod)%mod;
fac=fac*base%mod;
}
printf("%lld\n",res);
}
return 0;
}
参考博客:
https://oi-wiki.org/string/lyndon/
https://www.cnblogs.com/zwfymqz/p/10198690.html
https://www.cnblogs.com/st1vdy/p/13362219.html