【传送门:BZOJ3998】
简要题意:
对于一个给定长度为N的字符串,求它的第K小子串是什么
题解:
后缀自动机
首先对于T=0的时候,所有的能到达的不同状态,Right集合大小恒为1
T=1的时候,就累加
然后先判断子串数量是否超过K
如果没有,则直接DFS就好了
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; struct SAM { int son[27],dep,fail; }tr[1100000];int cnt,root,last; int a[510000]; void add(int k) { int x=a[k]; int np=++cnt,p=last; tr[np].dep=k; while(p!=0&&tr[p].son[x]==0) tr[p].son[x]=np,p=tr[p].fail; if(p==0) tr[np].fail=root; else { int q=tr[p].son[x]; if(tr[q].dep==tr[p].dep+1) tr[np].fail=q; else { int nq=++cnt;tr[nq]=tr[q]; tr[nq].dep=tr[p].dep+1; tr[q].fail=tr[np].fail=nq; while(p!=0&&tr[p].son[x]==q) tr[p].son[x]=nq,p=tr[p].fail; } } last=np; } char st[510000]; int Rsort[510000],r[1100000],sum[1100000],sa[1100000]; int k; void dfs(int x) { if(k<=r[x]) return ; k-=r[x]; for(int i=1;i<=26;i++) { int y=tr[x].son[i]; if(y==0) continue; if(k>sum[y]) k-=sum[y]; else { printf("%c",i+'a'-1); dfs(y); return ; } } } int main() { scanf("%s",st+1); int len=strlen(st+1); cnt=last=root=1; for(int i=1;i<=len;i++) a[i]=st[i]-'a'+1,add(i); for(int i=1;i<=cnt;i++) Rsort[tr[i].dep]++; for(int i=1;i<=len;i++) Rsort[i]+=Rsort[i-1]; for(int i=cnt;i>=1;i--) sa[Rsort[tr[i].dep]--]=i; int p=root; for(int i=1;i<=len;i++) p=tr[p].son[a[i]],r[p]++; int T; scanf("%d%d",&T,&k); for(int i=cnt;i>=1;i--) { if(T==0) r[tr[sa[i]].fail]=1; else r[tr[sa[i]].fail]+=r[sa[i]]; } r[root]=0; for(int i=cnt;i>=1;i--) { int p=sa[i];sum[p]=r[p]; for(int j=1;j<=26;j++) if(tr[p].son[j]!=0) sum[p]+=sum[tr[p].son[j]]; } if(k>sum[root]) printf("-1"); else dfs(root); printf(" "); return 0; }