3998: [TJOI2015]弦论
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 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
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");
}