题目描述
为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?
输入输出格式
输入格式:
第一行是一个仅由小写英文字母构成的字符串s
第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。
输出格式:
输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-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;
}