[TJOI2015]弦论

题目描述

为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

输入输出格式

输入格式:

 

第一行是一个仅由小写英文字母构成的字符串s

第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

 

输出格式:

 

输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

 

输入输出样例

输入样例#1: 
aabc
0 3
输出样例#1: 
aab
输入样例#2: 
aabc
1 3
输出样例#2: 
aa
输入样例#3: 
aabc
1 11
输出样例#3: 
-1

说明

数据范围

对于10%的数据,n ≤ 1000。

对于50%的数据,t = 0。

对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。

 

建出后缀自动机之后,记录一下每个节点有多少个可以到达的字串。。

t=0的时候每个节点的权值是1,否则就是它的right集合的大小。。

然后一遍dfs预处理之后再扫一遍就可以得到答案了。。。

 

#include<bits/stdc++.h>
#define ll long long
#define maxn 2000050
using namespace std;
int a[maxn],c[maxn],pre=1;
int f[maxn],ch[maxn][26],cnt=1;
int l[maxn],siz[maxn],n,k,t;
ll tot[maxn];
char s[maxn];

inline void ins(int x){
    int p=pre,np=++cnt;
    pre=np,l[np]=l[p]+1;
    siz[np]=1;
    
    for(;p&&!ch[p][x];p=f[p]) ch[p][x]=np;
    if(!p) f[np]=1;
    else{
        int q=ch[p][x];
        if(l[q]==l[p]+1) f[np]=q;
        else{
            int nq=++cnt;
            l[nq]=l[p]+1;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            f[nq]=f[q];
            f[q]=f[np]=nq;
            for(;ch[p][x]==q;p=f[p]) ch[p][x]=nq;
        }
    }
}

inline void build(){
    for(int i=0;i<n;i++) ins(s[i]-'a');
    if(t){
        for(int i=1;i<=cnt;i++) c[l[i]]++;
        for(int i=n;i>=0;i--) c[i]+=c[i+1];
        for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
        
        for(int i=1;i<=cnt;i++){
            int now=a[i];
            siz[f[now]]+=siz[now];
        }
    }
    else{
        fill(siz+1,siz+cnt+1,1);
    }
}

void dfs1(int x){
    tot[x]=siz[x];
    for(int i=0;i<26;i++) if(ch[x][i]){
        if(!tot[ch[x][i]]) dfs1(ch[x][i]);
        tot[x]+=tot[ch[x][i]];
    }
}

void dfs2(int x){
    if(k<=siz[x]){
        k=0,puts("");
        return;
    }
    
    k-=siz[x];
    
    for(int i=0;i<26;i++) if(ch[x][i]){
        if(k>tot[ch[x][i]]) k-=tot[ch[x][i]];
        else putchar('a'+i),dfs2(ch[x][i]);
        
        if(!k) return;
    }
}

inline void solve(){
    siz[1]=0;
    dfs1(1);
    if(k>tot[1]) puts("-1");
    else dfs2(1);
}

int main(){
    scanf("%s",s),n=strlen(s);
    scanf("%d%d",&t,&k);
    build();
    solve();
    return 0;
}

  

posted @ 2018-02-24 15:44  蒟蒻JHY  阅读(426)  评论(0编辑  收藏  举报