[TJOI2015]弦论

[TJOI2015]弦论

Time Limit: 10 Sec  Memory Limit: 256 MB
[Submit][Status][Discuss]

Description

对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

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

第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

Output

输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

aabc
0 3

Sample Output

aab

HINT

 

 N<=5*10^5


T<2

K<=10^9
分析:第K小字符串,可重或者不重;
   对于可重,直接累加后继个数;
   对于不重,每个状态标记为1个即可;
   然后dfs搜索答案即可;
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#define rep(i,m,n) for(i=m;i<=(int)n;i++)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
#define ls (rt<<1)
#define rs (rt<<1|1)
#define all(x) x.begin(),x.end()
const int maxn=1e6+10;
const int N=5e4+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}
int n,m,k,t;
struct samnode{
    samnode *son[26] , *f;
    int l , now, sc;
}*root,*last,sam[maxn],*b[maxn];
int cnt,num[maxn];
char a[maxn],ret[maxn];
void init(){
    root = last = &sam[cnt=0];
}
void add(int x)
{
    samnode *p = &sam[++cnt] , *jp=last;
    p->l = jp->l+1;
    last = p;
    for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x]=p;
    if(!jp) p->f = root;
    else{
        if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
        else{
            samnode *r = &sam[++cnt] , *q = jp->son[x];
            *r = *q;
            r->l = jp->l+1;
            q->f = p->f = r;
            for( ; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
        }
    }
}
int main(){
    int i,j;
    init();
    scanf("%s%d%d",a,&t,&k);
    int len=strlen(a);
    rep(i,0,len-1)add(a[i]-'a');
    samnode *go=root;
    rep(i,0,len-1)go=go->son[a[i]-'a'],go->now=1;
    rep(i,0,cnt)num[sam[i].l]++;
    rep(i,1,len)num[i]+=num[i-1];
    rep(i,0,cnt)b[--num[sam[i].l]]=&sam[i];
    if(!t)rep(i,1,cnt)sam[i].now=1;
    if(t)for(i=cnt;i>=1;i--)b[i]->f->now+=b[i]->now;
    b[0]->sc=b[0]->now=0;
    for(i=cnt;i>=0;i--)
    {
        b[i]->sc=b[i]->now;
        rep(j,0,25)if(b[i]->son[j])b[i]->sc+=b[i]->son[j]->sc;
    }
    if(b[0]->sc<k)
    {
        puts("-1");
        return 0;
    }
    go=root;
    int tot=0;
    while(k>0)
    {
        rep(i,0,25)
        {
            if(go->son[i])
            {
                if(go->son[i]->sc>=k)
                {
                    ret[++tot]=i+'a';
                    k-=go->son[i]->now;
                    go=go->son[i];
                    break;
                }
                else k-=go->son[i]->sc;
            }
        }
    }
    ret[++tot]=0;
    printf("%s\n",ret+1);
    return 0;
}
posted @ 2017-10-03 22:49  mxzf0213  阅读(234)  评论(0编辑  收藏  举报