bzoj3998: [TJOI2015]弦论
一道后缀自动机的简单题;
对串建立后缀自动机,然后基排算每个点的right集合大小,它能到达的点集的大小,它能到达的点集的right集合大小。
然后直接在自动机上跑就好了。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=1e6+7;
typedef long long LL;
using namespace std;
int T,k,len,cnt;
char s[N],ans[N];
template<typename T> void read(T &x) {
T f=1; x=0; char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int rt=1,tot=1,last=1,ch[N][26],fa[N],ln[N];
LL sz[N],sz2[N],sum[N],summ;
void insert(int x) {
int p=last,np=++tot; last=np;
ln[np]=ln[p]+1; sz2[np]=1;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=rt;
else {
int q=ch[p][x];
if(ln[q]==ln[p]+1) fa[np]=q;
else {
int nq=++tot; ln[nq]=ln[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
void calc() {
static int c[N],sa[N];
for(int i=2;i<=tot;i++) c[ln[i]]++;
for(int i=2;i<=len;i++) c[i]+=c[i-1];
for(int i=2;i<=tot;i++) sa[c[ln[i]]--]=i;
for(int i=tot-1;i>=1;i--) {
int x=sa[i],y=fa[x];
sz2[y]+=sz2[x];
for(int j=0;j<26;j++) {
sum[x]+=sum[ch[x][j]];
sz[x]+=sz[ch[x][j]];
}
sum[x]+=sz2[x];
sz[x]++;
}
for(int i=0;i<26;i++)
summ+=sz[ch[rt][i]];
}
int travel(int k) {
int x=rt;
while(k) {
for(int i=0;i<26;i++) {
int y=ch[x][i];
if(sz[y]>=k) {
ans[cnt++]='a'+i;
if(T==0) k--;
else k-=sz2[y];
k=max(k,0);
x=y;
break;
}
else {
if(T==0) k-=sz[y];
else k-=sum[y];
}
}
}
}
int main() {
scanf("%s",s);
read(T); read(k);
len=strlen(s);
for(int i=0;i<len;i++) insert(s[i]-'a');
calc();
if((T==1&&len*(len+1)/2<k)||(T==0&&summ<k)) {
puts("-1");
return 0;
}
travel(k);
puts(ans);
return 0;
}