题目大意:求严格/非严格K小子串
题解:先建立SAM
按mx排序得到拓扑序
统计一个点向后得到不同字串数
T=0,主链上的点都是1,然后在parent树上把儿子加到父亲上去
T=1,计算每一个点right集合的大小
最后在自动机上暴力找第k小的然后输出即可
我的收获:2233
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int T,n,K;
char S[N];
struct Suffix_Automaton{
int root,last,cnt;
int ch[N][26],fail[N];
int mx[N],val[N],sum[N];
int v[N],q[N];
Suffix_Automaton(){root=1,last=1,cnt=1;}
void extend(int c){
int p=last,np=last=++cnt;
mx[np]=mx[p]+1;val[np]=1;
for(;p&&!ch[p][c];p=fail[p]) ch[p][c]=np;
if(!p) fail[np]=root; else{
int q=ch[p][c];
if(mx[p]+1==mx[q]) fail[np]=q; else{
int nq=++cnt;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fail[nq]=fail[q],fail[np]=fail[q]=nq;
for(;ch[p][c]==q;p=fail[p]) ch[p][c]=nq;
}
}
}
void pre(){
for(int i=1;i<=cnt;i++) v[mx[i]]++;
for(int i=1;i<=n;i++) v[i]+=v[i-1];
for(int i=cnt;i;i--) q[v[mx[i]]--]=i;
for(int i=cnt;i;i--){
int t=q[i];
if(T==1) val[fail[t]]+=val[t];
else val[t]=1;
}
val[1]=0;
for(int i=cnt;i;i--)
{
int t=q[i];sum[t]=val[t];
for(int j=0;j<26;j++)
sum[t]+=sum[ch[t][j]];
}
}
void dfs(int x,int K){
if(K<=val[x]) return ;
K-=val[x];
for(int i=0;i<26;i++)
{
int t=ch[x][i];
if(K<=sum[t]){putchar(i+'a');dfs(t,K);return ;}
K-=sum[t];
}
}
}Sam;
void init()
{
scanf("%s",S+1);n=strlen(S+1);
scanf("%d%d",&T,&K);
for(int i=1;i<=n;i++) Sam.extend(S[i]-'a');
Sam.pre();
if(K>Sam.sum[1]) puts("-1");
else Sam.dfs(1,K);
}
int main()
{
init();
return 0;
}