bzoj3998: [TJOI2015]弦论

传送门

一道后缀自动机的简单题;

对串建立后缀自动机,然后基排算每个点的right集合大小,它能到达的点集的大小,它能到达的点集的right集合大小。

然后直接在自动机上跑就好了。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=1e6+7;
typedef long long LL;
using namespace std;
int T,k,len,cnt;
char s[N],ans[N];

template<typename T> void read(T &x) {
    T f=1; x=0; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

int rt=1,tot=1,last=1,ch[N][26],fa[N],ln[N];
LL sz[N],sz2[N],sum[N],summ;
void insert(int x) {
    int p=last,np=++tot; last=np;
    ln[np]=ln[p]+1; sz2[np]=1;
    for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
    if(!p) fa[np]=rt;
    else {
        int q=ch[p][x];
        if(ln[q]==ln[p]+1) fa[np]=q;
        else {
            int nq=++tot; ln[nq]=ln[p]+1;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            fa[nq]=fa[q]; fa[q]=fa[np]=nq; 
            for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
        }
    }
}

void calc() {
    static int c[N],sa[N];
    for(int i=2;i<=tot;i++) c[ln[i]]++;
    for(int i=2;i<=len;i++) c[i]+=c[i-1];
    for(int i=2;i<=tot;i++) sa[c[ln[i]]--]=i;
    for(int i=tot-1;i>=1;i--) {
        int x=sa[i],y=fa[x];
        sz2[y]+=sz2[x];
        for(int j=0;j<26;j++) {
            sum[x]+=sum[ch[x][j]];
            sz[x]+=sz[ch[x][j]];
        }
        sum[x]+=sz2[x];
        sz[x]++;
    }
    for(int i=0;i<26;i++) 
    summ+=sz[ch[rt][i]]; 
}

int travel(int k) {
    int x=rt;
    while(k) {
        for(int i=0;i<26;i++) {
            int y=ch[x][i];
            if(sz[y]>=k) {
                ans[cnt++]='a'+i;
                if(T==0) k--;
                else k-=sz2[y];
                k=max(k,0);
                x=y;
                break;
            }
            else {
                if(T==0) k-=sz[y];
                else k-=sum[y];
            }
        }
    } 
}

int main() {
    scanf("%s",s);
    read(T); read(k);
    len=strlen(s);
    for(int i=0;i<len;i++) insert(s[i]-'a');
    calc();
    if((T==1&&len*(len+1)/2<k)||(T==0&&summ<k)) {
        puts("-1");
        return 0;
    }
    travel(k);
    puts(ans);
    return 0;
}
View Code

 

posted @ 2018-01-05 21:16  啊宸  阅读(162)  评论(0编辑  收藏  举报