其他分享
首页 > 其他分享> > EOJ 7月月赛

EOJ 7月月赛

作者:互联网

EOJ 7月月赛

D. 给你一个字符串,你现在需要的是将它的每一个前缀看成单独的字符串,最终组成最大的一个整数。

​ 分析,可以想到,两个前缀A,B组成的字符串,其大小由相对顺序决定,不妨设|A|<|B|。B=A+X,则最终的大小取决于A+X于X+A的字典序大小。这个直接通过SA就可以解决。最终通过排序来解决。

#include<bits/stdc++.h>

using namespace std;

const int N = 100005;

const int MOD = 998244353;

int sa[N], rk[N], c[N], h[N], x[N], y[N];

int rmq[N][21], n, base=10;

int lg[N], pw[N], arr[N], val[N];

char s[N];

void SA(){
    int m=256;
    for(int i=1;i<=m;++i)c[i]=0;
    for(int i=1;i<=n;++i)++c[x[i]=s[i]];
    for(int i=1;i<=m;++i)c[i]+=c[i-1];
    for(int i=n;i>=1;--i)sa[c[s[i]]--]=i;

    for(int k=1,p;k<=n;k<<=1){
        p=0;
        for(int i=n;i>n-k;--i)y[++p]=i;
        for(int i=1;i<=n;++i){
            if(sa[i]>k){
                y[++p]=sa[i]-k;
            }
        }

        for(int i=1;i<=m;++i)c[i]=0;
        for(int i=1;i<=n;++i)++c[x[i]];
        for(int i=1;i<=m;++i)c[i]+=c[i-1];
        for(int i=n;i>=1;--i)sa[c[x[y[i]]]--]=y[i];

        p=y[sa[1]]=1;
        for(int i=2,a,b;i<=n;++i){
            a=(sa[i]+k>n?-1:x[sa[i]+k]);
            b=(sa[i-1]+k>n?-1:x[sa[i-1]+k]);

            y[sa[i]]=(x[sa[i]]==x[sa[i-1]]&&a==b?p:++p);
        }

        if(p>=n)break;

        m=p;
        swap(x,y);
    }

    for(int i=1;i<=n;++i){
        rk[sa[i]]=i;
    }
}

void getHeight(){
    for(int i=1, k=0;i<=n;++i){
        if(k)--k;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])++k;
        h[rk[i]]=k;
    }
}

void init(){
    SA();
    getHeight();

    for(int i=1;i<=n;++i)rmq[i][0]=h[i];
    for(int j=1;j<=20;++j){
        for(int i=1;i+(1<<j)-1<=n;++i){//bug
            rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<j-1)][j-1]);
        }
    }
}

int LCP(int l, int r){
    l=rk[l];r=rk[r];
    ++l,++r;
    if(l>r)swap(l,r);
    --r;

    int k=lg[r-l+1];
    return min(rmq[l][k],rmq[r-(1<<k)+1][k]);
}


bool cmp(int l, int r){
    if(l>r)return !cmp(r,l);

    int c=LCP(1,l+1);
    int len=r-l;

    if(c<len){
        return rk[l+1]<rk[1];
    }else{
        return rk[1]<rk[len+1];
    }
}

int main(){
    lg[0]=-1;
    for(int i=1;i<=100000;++i)lg[i]=lg[i>>1]+1;
    scanf("%s", s+1);
    n=strlen(s+1);
    init();

    pw[0]=1;
    for(int i=1;i<=n;++i){
        val[i]=(1ll*val[i-1]*base+s[i]-'0')%MOD;
        pw[i]=1ll*pw[i-1]*base%MOD;
        arr[i]=i;
    }

    sort(arr+1,arr+n+1,cmp);

    int ans=0;
    for(int i=1;i<=n;++i)ans=(1ll*ans*pw[arr[i]]+val[arr[i]])%MOD;

    if(ans<0)ans+=MOD;

    printf("%d",ans);

    return 0;
}

其他题都没啥营养,咕咕咕。

标签:rmq,int,EOJ,++,字符串,--,sa
来源: https://www.cnblogs.com/JohnRan/p/13360151.html