[TJOI2015]弦论

Posted ah2002

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[TJOI2015]弦论相关的知识,希望对你有一定的参考价值。

我们先求出该字符串的(SA)(Ht)

然后分类讨论

(T=0)时,每次去掉(Ht)往后扫就行

(T=1)时,我们考虑(lcp)对答案的影响

既然用到(lcp),那就要用(ST)表维护

左端点固定时,随右端点的增大,区间(min)单调不升

我们就可以用二分+限制右端点的方式统计某个后缀的前缀的贡献

循环遍历每个后缀时,由于(Ht)部分已经统计过对答案的贡献,就不用再计算了,从(Ht+1)的位置继续向后统计即可

#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std;

const int MAXN=5e5+5;

int ln,maxn,p,t;
int SA[MAXN],id[MAXN],rnk[MAXN],bnk[MAXN],Ht[MAXN];
char ch[MAXN];
int ST[19][MAXN],lg[MAXN];

void shel()
{
    for(int i=1;i<=ln;++i) ++bnk[rnk[id[i]]];
    for(int i=1;i<=maxn;++i) bnk[i]+=bnk[i-1];
    for(int i=1;i<=ln;++i) SA[++bnk[rnk[id[i]]-1]]=id[i];
    for(int i=0;i<=maxn;++i) bnk[i]=0;
    return;
}

void GetSA()
{
    for(int i=1;i<=ln;++i) rnk[i]=ch[i],id[i]=i,maxn=max(maxn,rnk[i]);
    shel();
    for(int k=1;k<ln;k<<=1){
        for(int i=1;i<=k;++i) id[i]=ln-k+i;
        int ct=k;
        for(int i=1;i<=ln;++i) if(SA[i]>k) id[++ct]=SA[i]-k;
        shel();swap(id,rnk);rnk[SA[1]]=1;
        for(int i=2;i<=ln;++i) rnk[SA[i]]=(id[SA[i]]==id[SA[i-1]]&&id[SA[i]+k]==id[SA[i-1]+k])?rnk[SA[i-1]]:rnk[SA[i-1]]+1;
        if(rnk[SA[ln]]==ln) return;
        maxn=rnk[SA[ln]];
    }return;
}

void GetHt()
{
    int k=0;
    for(int i=1;i<=ln;++i){
        if(rnk[i]==1) continue;
        if(k) --k;
        int ct=SA[rnk[i]-1];
        while(ct+k<=ln&&i+k<=ln&&ch[i+k]==ch[ct+k]) ++k;
        Ht[rnk[i]]=k;
    }return;
}

int Getmi(int l,int r){int tmp=lg[r-l+1];return min(ST[tmp][l+(1<<tmp)-1],ST[tmp][r]);}

void slv1()
{
    for(int i=1;i<=ln;++i) lg[i]=i>>lg[i-1]+1?lg[i-1]+1:lg[i-1];
    for(int i=1;i<=ln;++i) ST[0][i]=Ht[i];
    for(int j=1;j<=lg[ln];++j){
        int tmp=1<<j-1;
        for(int i=tmp<<1;i<=ln;++i){
            ST[j][i]=min(ST[j-1][i],ST[j-1][i-tmp]);
        }
    }for(int i=1;i<=ln;++i){
        int tmp=SA[i]+Ht[i];
        int ct=ln;
        while(1){
            if(tmp>ln) break;
            if(ct==i){
                if(t>ln-tmp+1){t-=ln-tmp+1;break;}
                for(int j=SA[i];j<=tmp+t-1;++j) putchar(ch[j]);
                return;
            }int l=i,r=ct;
            while(l<r){
                int mid=l+r+1>>1;
                if(Getmi(i+1,mid)>=tmp-SA[i]+1) l=mid;
                else r=mid-1;
            }ct=r;
            if(t>r-i+1) t-=r-i+1;
            else{
                for(int j=SA[i];j<=tmp;++j) putchar(ch[j]);
                return;
            }++tmp;
        }
    }puts("-1");
    return;
}

void slv2()
{
    int ct=1;
    while(t>ln-SA[ct]-Ht[ct]+1) t-=ln-SA[ct]-Ht[ct]+1,++ct;
    if(ct>ln){puts("-1");return;}
    for(int i=SA[ct];i<=SA[ct]+t+Ht[ct]-1;++i) putchar(ch[i]);
    puts("");
    return;
}

int main()
{
    scanf("%s",ch+1);ln=strlen(ch+1);
    GetSA();GetHt();scanf("%d%d",&p,&t);
    p?slv1():slv2();
    return 0;
}

以上是关于[TJOI2015]弦论的主要内容,如果未能解决你的问题,请参考以下文章

TJOI2015 弦论

[TJOI2015]弦论

P3975 [TJOI2015]弦论

BZOJ3998 TJOI2015 弦论 后缀自动机

[TJOI2015]弦论 - 后缀自动机

bzoj3998: [TJOI2015]弦论