题目大意

解题思路
建出sam,对于零的情况直接统计儿子节点,对于一的情况统计right集的大小,统计子树和,走的时候看子树有多少种串,K大于它就直接减,看下一个,不然就递归进去,减去当前节点的贡献。
code
using namespace std;
int const mn=5*1e5+9,mp=1e6+9,inf=1e9+7;
int t,K,n,pon,f[mp],g[mp],son[mp][26],fa[mp],mx[mp],du[mp],qu[mp];
char s[mn];
int main(){
//freopen("string.in","r",stdin);
//freopen("string.out","w",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%s",s+1);n=strlen(s+1);
fo(i,1,n)s[i]-='a';
scanf("%d%d",&t,&K);
int last=pon=1;
fo(i,1,n){
int p=last,np=last=++pon;
mx[np]=mx[p]+1;f[np]=1;
for(;p&&(!son[p][s[i]]);p=fa[p])son[p][s[i]]=np;
if(!p){fa[np]=1;continue;}
int q=son[p][s[i]];
if(mx[p]+1==mx[q])fa[np]=q;
else{
int nq=++pon;mx[nq]=mx[p]+1;
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
fo(j,0,25)son[nq][j]=son[q][j];
for(;p&&(son[p][s[i]]==q);p=fa[p])son[p][s[i]]=nq;
}
p=np;
}
fo(i,1,pon)du[fa[i]]++;
int he=0,ti=0;
fo(i,1,pon)if(!du[i])qu[++ti]=i;
while(he!=ti){
int now=qu[++he],next=fa[now];
du[next]--;
f[next]+=f[now];
if(!du[next])qu[++ti]=next;
}
if(!t)fo(i,1,pon)f[i]=1;
fo(i,1,pon)g[i]=f[i];
fo(i,1,pon)fo(j,0,25)du[son[i][j]]++;
he=0,ti=0;
qu[++ti]=1;du[0]++;
while(he!=ti){
int now=qu[++he];
fo(i,0,25){
int next=son[now][i];
du[next]--;
if(!du[next])qu[++ti]=next;
}
}
fd(i,ti,1)fo(j,0,25){
int now=qu[i],next=son[now][j];
if(next)g[now]+=g[next];
}
int now=1;
if(K>g[1]){printf("-1");return 0;}
while(1){
fo(i,0,25){
int next=son[now][i];
if(!next)continue;
if(g[next]<K)K-=g[next];
else{
printf("%c",'a'+i);
K-=f[next];
now=next;
if(K<=0)return 0;
break;
}
}
}
return 0;
}