先统计出每个节点代表的子串个数,如果去重就是 1 <script type="math/tex" id="MathJax-Element-30">1</script>,不去重就是right集合的大小。因为后缀自动机是一个DAG,可以预处理子节点大小之和然后dfs一遍。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=1000010;
char s[maxn];
int trans[maxn][27],fail[maxn],val[maxn],cnt[maxn],que[maxn],
n,t,k,tot=1;
LL size[maxn],num[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int last=1,p,np,q,nq,x;
scanf("%s%d%d",s+1,&t,&k);
n=strlen(s+1);
for (int i=1;i<=n;i++)
{
x=s[i]-'a'+1;
p=last;
val[last=np=++tot]=val[p]+1;
while (p&&!trans[p][x])
{
trans[p][x]=np;
p=fail[p];
}
if (!p) fail[np]=1;
else
{
q=trans[p][x];
if (val[q]==val[p]+1) fail[np]=q;
else
{
val[nq=++tot]=val[p]+1;
fail[nq]=fail[q];
fail[np]=fail[q]=nq;
for (int j=1;j<=26;j++) trans[nq][j]=trans[q][j];
while (p&&trans[p][x]==q)
{
trans[p][x]=nq;
p=fail[p];
}
}
}
}
for (int i=1;i<=tot;i++) cnt[val[i]]++;
for (int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
for (int i=1;i<=tot;i++) que[cnt[val[i]]--]=i;
if (t)
{
p=1;
for (int i=1;i<=n;i++)
{
p=trans[p][s[i]-'a'+1];
num[p]++;
}
for (int i=tot;i;i--) num[fail[que[i]]]+=num[que[i]];
num[1]=0;
}
else for (int i=2;i<=tot;i++) num[i]=1;
for (int i=tot;i;i--)
{
size[que[i]]=num[que[i]];
for (int j=1;j<=26;j++)
size[que[i]]+=size[trans[que[i]][j]];
}
if (size[1]<k)
{
printf("-1\n");
return 0;
}
p=1;
while (k>num[p])
{
k-=num[p];
for (int j=1;j<=26;j++)
if (trans[p][j])
{
if (k>size[trans[p][j]]) k-=size[trans[p][j]];
else
{
printf("%c",'a'+j-1);
p=trans[p][j];
break;
}
}
}
}