2020杭电多校(一) Minimum Index(lyndon分解)

学习完lyndon分解后,我们发现这个分解可以分割字符串并且分割成a[i]>=a[i+1]且每个字符串都是自己的最小后缀

因此在分解的过程中

当遇到s[j]==s[k],这说明前面都是循环的字符串,那么答案就是上一个同样位置的答案后移一个循环节长度

如果s[j]<s[k],这说明马上整串都变成一个lyndon字符串了,因此答案就是开头位置是最小的。

如果s[j]>s[k]那就说明当前循环节的答案是错误的,不过因为本身在求lyndon字符串的时候,指针就会跳转到当前循环节首位,所以只需要重算一遍就行了

注意初始化,因为刚开始只有一个字符,因此答案是自身

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e6+10;
const int mod=1e9+7;
const int BAS=1112;
string s;
int p[N];
int f[N];
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    f[0]=1;
    for(int i=1;i<N;++i) f[i]=1LL*f[i-1]*BAS%mod;
    while(t--){
        string s;
        cin>>s;
        int n=(int)s.size();
        s=" "+s;
        for(int i=1;i<=n;){
            int j=i,k=i+1;
            p[i]=i;
            while(k<=n&&s[j]<=s[k]){
                if(s[j]<s[k]){
                    p[k]=i;
                    j=i;
                }
                else{
                    p[k]=p[j]+(k-j);
                    j++;
                }
                k++;
            }
            while(i<=j){
                i+=k-j;
            }
        }
        ll ans=0;
        for(int i=1;i<=n;++i)
            ans=(ans+1ll*f[i-1]*(p[i]))%mod;
        cout<<ans<<endl;
    }
}
View Code

 

posted @ 2020-07-27 10:57  朝暮不思  阅读(198)  评论(0编辑  收藏  举报