[TJOI2015]弦论(后缀自动机)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvmaooi/article/details/82668836

3998: [TJOI2015]弦论

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











解:

居然一遍写对后缀自动机哈哈哈。
很简单的做法。先算出每个节点算出现几次,如果t=0就是全部出现一次,否则就是把非复制节点赋值1拓扑序上推一波。
接着在自动机上跑一边dp(一开始以为是树形结构,没跑dp。。。),记录每个点向下跑可以得到多少串。
贪心一下即可。

code:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct lxy{
    int to[26],p,len;
    long long num,f;
}a[1000005];

int cnt=1,las=1,t,len;
int tax[500005],tp[1000005];
long long k;
char s[500005];

void insert(int c,int w){
    a[++cnt].len=w;a[cnt].num=1;
    int i;for(i=las;a[i].to[c]==0&&i!=0;i=a[i].p) a[i].to[c]=cnt;
    las=cnt;
    if(i==0){
        a[cnt].p=1;return;
    }
    int q=a[i].to[c],nq;
    if(a[i].len+1==a[q].len){
        a[cnt].p=q;return;
    }
    nq=++cnt;a[nq]=a[q];a[nq].len=a[i].len+1;a[nq].num=0;
    for(int j=i;a[j].to[c]==q;j=a[j].p) a[j].to[c]=nq;
    a[q].p=nq;a[las].p=nq;
}

void findtp(){
    for(int i=1;i<=cnt;i++) tax[a[i].len]++;
    for(int i=1;i<=len;i++) tax[i]+=tax[i-1];
    for(int i=1;i<=cnt;i++) tp[tax[a[i].len]--]=i;
}

void dfs(int u){
    a[u].f=a[u].num;
    for(int i=0;i<=25;i++)
      if(a[u].to[i]!=0){
        if(a[a[u].to[i]].f==0) dfs(a[u].to[i]);
        a[u].f+=a[a[u].to[i]].f;
      }
}

void findans(int u){
    if(k<=a[u].num) return;
    k-=a[u].num;
    for(int i=0;i<=25;i++)
      if(a[u].to[i]!=0){
        if(a[a[u].to[i]].f>=k){
            printf("%c",i+'a');
            findans(a[u].to[i]);
            return;
        }
        else k-=a[a[u].to[i]].f;
      }
}

int main()
{
    scanf("%s",s+1);
    len=strlen(s+1);
    for(int i=1;i<=len;i++) insert(s[i]-'a',i);
    scanf("%d%lld",&t,&k);
    findtp();
    for(int i=cnt;i>=1;i--) a[a[tp[i]].p].num+=a[tp[i]].num;
    if(t==0)
      for(int i=1;i<=cnt;i++) a[i].num=1;
    a[1].num=0;
    dfs(1);
    if(k>a[1].f){
        printf("-1");
        return 0;
    }
    findans(1);
}

猜你喜欢

转载自blog.csdn.net/lvmaooi/article/details/82668836
今日推荐