题意:
遍历字符串,求所有前缀的最小后缀,最后求和。
题解:
这题使用到Lyndon Word的知识,🖱️
对于字符串 𝑆,若 𝑆 的最小后缀为其本身,那么称 𝑆 为 Lyndon 串(Lyndon Word),
任意字符串都可以分解成S=t1t2t3…tk,t表示已经确定的Lyndon串,该分解是唯一的,并且有ti<=ti+1的性质。
用三个循环变量 𝑖,𝑗,𝑘 维持一个循环不变式:
·S[1…𝑖−1]=S1S2⋯S𝑔 是已经固定下来的分解,满足 S𝑙 是 Lyndon 串,且 S𝑙≤S𝑙+1。
·𝑗−𝑖是当前最长的 Lyndon prefix 的长度,即 S[𝑗] 是 S[𝑘] 在 Lyndon Prefix 中对应位置的字符。
·𝑘是当前读入的字符的位置。
那么,
当Sj = Sk时,有 ans[k] = ans[j] + j - k;
当Sj < Sk时,此时Si…k 是一个Lyndon串,j还原到i继续执行相同的步骤;
当Sj > Sk 时,则递归求解,先分解完 S[𝑖…𝑡] ,然后将指针指向 𝑡+1 重新进行算法过程。
复杂度为O(n)。
AC_CODE:
const int maxn = 4e6+5;
char s[maxn];
int lyndon[maxn];
ll ans[maxn];
int N;
void Lyndon() {
ans[1] = 1;
for(int i=1; i<=N; ) {
int j=i,k=i+1;
ans[k] = k;
while(s[j] <= s[k]) {
if(s[j] == s[k]) {
ans[k] = ans[j] + k - j, j += 1;//abcdab
}
else ans[k] = j = i;//abcdac
k += 1;
}
while(i<=j) i+=k-j;
ans[k] = i;//abcdaa
}
}
void solve(){
scanf("%s",s+1);
N = strlen(s+1);
Lyndon();
ll sum = 1;
ll temp = 1112;
FOR(i,2,N) {
sum = sum + ans[i] * temp % mod;
sum %= mod;
temp *= 1112;
temp %= mod;
}
printf("%lld\n",sum);
}