SP7258 SUBLEX - Lexicographical Substring Search(后缀自动机)
解题思路
首先建\(sam\),然后在拓扑序上\(dp\)一下,把每个点的路径数算出来,然后统计答案时就在自动机上\(dfs\)一下,仿照平衡树那样找第\(k\)小。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 90005;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,Q,l[MAXN<<1],fa[MAXN<<1],ch[MAXN<<1][27];
int lst,cnt,f[MAXN<<1],c[MAXN<<1],a[MAXN<<1];
char s[MAXN];
inline void Insert(int c){
int p=lst,np=++cnt;lst=np;l[np]=l[p]+1;
for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(l[q]==l[p]+1) fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
void query(int x){
int p=1;
while(x){
for(int i=1;i<=26;i++)if(ch[p][i]){
if(f[ch[p][i]]<x) x-=f[ch[p][i]];
else {p=ch[p][i];putchar('a'+i-1);x--;break;}
}
}
putchar('\n');
}
int main(){
scanf("%s",s+1);n=strlen(s+1);lst=cnt=1;
for(int i=1;i<=n;i++) Insert(s[i]-'a'+1);
for(int i=1;i<=cnt;i++) c[l[i]]++;
for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
for(int i=cnt;i;i--){
f[a[i]]=1;
for(int j=1;j<=26;j++)
f[a[i]]+=f[ch[a[i]][j]];
}
f[1]--;Q=rd();int x;
while(Q--){x=rd();query(x);}
return 0;
}