BZOJ 题目3998: [TJOI2015]弦论(后缀自动机求排名第k的子串,可重复)

3998: [TJOI2015]弦论

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 848   Solved: 274
[ 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

Source

ac代码

/**************************************************************
    Problem: 3998
    User: kxh1995
    Language: C++
    Result: Accepted
    Time:5204 ms
    Memory:126784 kb
****************************************************************/
 
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 1000020
char str[N];
int cot,last;
int fa[N],son[N][26],len[N],b[N],n;
int g[N],cnt[N],val[N];
void add(int c,int l)
{
    int p,np;
    p=last;
    np=last=++cot;
    len[np]=++n;
    val[np]=1;
    while(p&&!son[p][c])
    {
        son[p][c]=np;
        p=fa[p];
    }
    if(!p)
    {
        fa[np]=1;
    }
    else
    {
        int q=son[p][c];
        if(len[p]+1==len[q])
            fa[np]=q;
        else
        {
            int nq=++cot;
            len[nq]=len[p]+1;
            memcpy(son[nq],son[q],sizeof(son[q]));
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            while(son[p][c]==q)
            {
                son[p][c]=nq;
                p=fa[p];
            }
        }
    }
}
void build()
{
    cot=last=1;
    n=0;
    /*  memset(son,0,sizeof(son));
    memset(len,0,sizeof(len));
    memset(b,0,sizeof(b));
    memset(fa,0,sizeof(fa));*/
    int i,j;
    //  int Len=strlen(str);
    for(i=0;str[i];i++)
        add(str[i]-'a',i+1);
    for(i=1;i<=cot;i++)
    {
        cnt[len[i]]++;
    }
    for(i=1;i<=n;i++)
    {
        cnt[i]+=cnt[i-1];
    }
    for(i=1;i<=cot;i++)
    {
        b[cnt[len[i]]--]=i;
    }
}
int op,x;
void init()
{
    int i,j;
    for(i=cot;i;i--)
    {
        int t=b[i];
        if(op==1)
            val[fa[t]]+=val[t];
        else
            val[t]=1;
    }
    val[1]=0;
    for(i=cot;i;i--)
    {
        int t=b[i];
        g[t]=val[t];
        for(j=0;j<26;j++)
        {
            g[t]+=g[son[t][j]];
        }
    }
}
void query(int x,int k)
{
    if(k<=val[x])
        return;
    k-=val[x];
    int i,j;
    for(i=0;i<26;i++)
    {
        int t=son[x][i];
        if(t)
        {
            if(k<=g[t])
            {
                printf("%c",'a'+i);
                query(t,k);
                return;
            }
            else
                k-=g[t];
        }
    }
}
int main()
{
    scanf("%s",str);
    build();
    scanf("%d%d",&op,&x);
    init();
    if(x>g[1])
        printf("-1");
    else
        query(1,x);
    printf("\n");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值