题意:给一个长度不超过90000的串S,每次询问它的所有不同子串中,字典序第K小的,询问不超过500个。
第一道自己做的1A的SAM啦啦啦
很简单,建SAM后跑kth就行了
也需要按val基数排序倒着推出来d[s]状态s的后继子串个数
跑kth的时候判断d[v]>=k的时候就跑到v,并且k应该是--哦,因为一个子串过去了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> using namespace std; const int N=2e5+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n,Q,k; char s[N]; struct State{ int ch[26],par,val; }t[N]; int sz,root,last; inline int nw(int _){t[++sz].val=_;return sz;} inline void iniSAM(){sz=0;root=last=nw(0);} void extend(int c){ int p=last,np=nw(t[p].val+1); for(;p&&!t[p].ch[c];p=t[p].par) t[p].ch[c]=np; if(!p) t[np].par=root; else{ int q=t[p].ch[c]; if(t[q].val==t[p].val+1) t[np].par=q; else{ int nq=nw(t[p].val+1); memcpy(t[nq].ch,t[q].ch,sizeof(t[q].ch)); t[nq].par=t[q].par; t[q].par=t[np].par=nq; for(;p&&t[p].ch[c]==q;p=t[p].par) t[p].ch[c]=nq; } } last=np; } int c[N],a[N],d[N]; void RadixSort(){ for(int i=2;i<=sz;i++) c[t[i].val]++; for(int i=1;i<=n;i++) c[i]+=c[i-1]; for(int i=2;i<=sz;i++) a[c[t[i].val]--]=i; } void dp(){ for(int i=sz-1;i>=1;i--){ int u=a[i]; d[u]=1; for(int j=0;j<26;j++) d[u]+=d[t[u].ch[j]];//,printf("ch %d %d ",t[u].ch[j],d[t[u].ch[j]]); //printf("state %d %d %d %d %d ",i,u,t[u].val,d[u],sd[u]); } } void kth(int k){ int u=root; while(k>0){//printf("hi %d %d ",k,u); for(int i=0;i<26;i++) if(t[u].ch[i]){ int v=t[u].ch[i];//printf("v %d %d %d ",v,d[v],sd[v]); if(d[v]>=k) {putchar('a'+i);k--;u=v;break;} else k-=d[v]; } } putchar(' '); } int main(){ freopen("in","r",stdin); scanf("%s",s+1); n=strlen(s+1); iniSAM(); for(int i=1;i<=n;i++) extend(s[i]-'a'); RadixSort(); dp(); Q=read(); while(Q--){ k=read(); kth(k); } }