好像是个经典问题,然而我没做过
建SAM,然后经过每个节点的子串数目就可以求了,多个相同子串算一个的话就把所有siz都搞成$1$,否则就是$right$集合的大小,然后就是常见的递推
求第$k$小是从根节点出发按字典序沿着trans往下走,每次输出对应的字符然后扣掉对应的数量
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=500005,M=1000005; 6 int fth[M],trs[M][26],len[M],siz[M]; 7 int rnk[M],bkt[M]; long long sum[M]; 8 int typ,kth,lth,lst,tot; 9 char str[N]; 10 void Insert(int ch) 11 { 12 int nde=lst,newn=++tot; lst=newn; 13 siz[newn]=1,len[newn]=len[nde]+1; 14 while(nde&&!trs[nde][ch]) 15 trs[nde][ch]=newn,nde=fth[nde]; 16 if(!nde) 17 fth[newn]=1; 18 else 19 { 20 int tran=trs[nde][ch]; 21 if(len[tran]==len[nde]+1) 22 fth[newn]=tran; 23 else 24 { 25 int rnde=++tot; len[rnde]=len[nde]+1; 26 for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i]; 27 fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde; 28 while(nde&&trs[nde][ch]==tran) 29 trs[nde][ch]=rnde,nde=fth[nde]; 30 } 31 } 32 } 33 int main() 34 { 35 register int i,j,k; 36 scanf("%s%d%d",str+1,&typ,&kth); 37 lth=strlen(str+1),lst=tot=1; 38 for(i=1;i<=lth;i++) Insert(str[i]-'a'); 39 for(i=1;i<=tot;i++) bkt[len[i]]++; 40 for(i=1;i<=lth;i++) bkt[i]+=bkt[i-1]; 41 for(i=1;i<=tot;i++) rnk[bkt[len[i]]--]=i; 42 for(i=tot;i;i--) 43 j=rnk[i],typ?siz[fth[j]]+=siz[j]:siz[j]=1; 44 siz[1]=0; 45 for(i=tot;i;i--) 46 { 47 j=rnk[i],sum[j]=siz[j]; 48 for(k=0;k<=25;k++) 49 if(trs[j][k]) sum[j]+=sum[trs[j][k]]; 50 } 51 if(kth>sum[1]) printf("-1"); 52 else 53 { 54 int nde=1; 55 while(kth-siz[nde]>0) 56 { 57 kth-=siz[nde]; 58 for(i=0;i<=25&&kth>sum[trs[nde][i]];i++) 59 kth-=sum[trs[nde][i]]; 60 nde=trs[nde][i],printf("%c",i+'a'); 61 } 62 } 63 return 0; 64 }