题目大意
解题思路
建出sam,对于零的情况直接统计儿子节点,对于一的情况统计right集的大小,统计子树和,走的时候看子树有多少种串,K大于它就直接减,看下一个,不然就递归进去,减去当前节点的贡献。
code
using namespace std;
int const mn=5 *1e5 +9 ,mp=1 e6+9 ,inf=1 e9+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 ;
}