题面:
题意:
给定一个字符串
求 ∑i=1npi∗1112i−1
其中, pi 是字符串 S 的前缀 Si 的所有后缀的最小后缀的位置。
题解:
考虑Lyndon 分解过程。
Lyndon 分解:读入一个字符串S,把这个字符串分解成若干部分 S=S1S2...Sk
其中每一个 Si都是Lyndon串,且有 Si>=Si+1
一个字符串S是一个Lyndon串,当且仅当S是其所有后缀中最小的字符串。
我们设当前读入的字符是 s[k],j=k−∣t∣,t 是正在循环的 Lyndon串。
如果 s[k]>s[j] 新的Lyndon串(循环)被固定下来,那么 Sk的 Pk=i
如果 s[k]=s[j] 周期 k−j继续保持, Pk等于其上一个循环节对应位置 最小后缀的位置往后移动一个循环节, j 是 k 上一个循环节所对应位置,那么 Pj往后移动一个循环节,即 Pj+k−j。
如果 s[k]==s[j]那么循环中的Lyndon串被固定下来。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x) (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=1000100;
const int maxm=100100;
const int up=100000;
ll p[maxn];
int pos[maxn];
char str[maxn];
int main(void)
{
p[0]=1;
for(int i=1;i<maxn;i++)
p[i]=p[i-1]*1112%mod;
int tt;
scanf("%d",&tt);
while(tt--)
{
scanf("%s",str+1);
int n=strlen(str+1);
for(int i=1;i<=n;)
{
int j=i,k=i+1;
//str[i]这个字符组成的字符串是找的最初始的lyndon串
pos[i]=i;
while(k<=n&&str[j]<=str[k])
{
if(str[j]<str[k]) pos[k]=i,j=i;
else pos[k]=pos[j]+k-j,j++;
k++;
}
while(i<=j) i+=k-j;
}
ll ans=0;
for(int i=1;i<=n;i++)
ans=(ans+p[i-1]*pos[i])%mod;
printf("%lld\n",ans);
}
return 0;
}