前几天写的题,今天补写个blog
T的情况get right集合的时候特判一下。
因为SAM就是有序的,所以可以dfs求解。
把parent树构建出来,sum表示当前子树的right和,搜一下就出来了。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int len,a[1100000]; struct node { int w[30]; }ch[1100000];int root,last,cnt; int dep[1100000],parent[1100000]; void add(int k) { int x=a[k]; int now=++cnt,p=last; dep[now]=k; while(p!=0&&ch[p].w[x]==0)ch[p].w[x]=now,p=parent[p]; if(p==0)parent[now]=root; else { int pre=ch[p].w[x]; if(dep[p]+1==dep[pre])parent[now]=pre; else { int npre=++cnt; ch[npre]=ch[pre]; dep[npre]=dep[p]+1; parent[npre]=parent[pre]; parent[now]=parent[pre]=npre; while(ch[p].w[x]==pre)ch[p].w[x]=npre,p=parent[p]; } } last=now; } int Rsort[1100000],sa[1100000]; int Right[1100000]; void get_Right(int T) { for(int i=1;i<=cnt;i++)Rsort[dep[i]]++; for(int i=1;i<=len;i++)Rsort[i]+=Rsort[i-1]; for(int i=cnt;i>=1;i--)sa[Rsort[dep[i]]--]=i; int now=root; for(int i=1;i<=len;i++) { int x=a[i]; now=ch[now].w[x]; Right[now]++; } for(int i=cnt;i>=1;i--) { if(T==1) Right[parent[sa[i]]]+=Right[sa[i]]; else Right[sa[i]]=1; } Right[root]=0; } int T,k; int sum[1100000]; void dfs(int now) { if(k<=Right[now])return ; k-=Right[now]; for(int x=1;x<=26;x++) { if(ch[now].w[x]!=0) { int next=ch[now].w[x]; if(k>sum[next])k-=sum[next]; else { printf("%c",x+‘a‘-1); dfs(next); return ; } } } } char ss[1100000]; int main() { scanf("%s",ss+1);len=strlen(ss+1); for(int i=1;i<=len;i++)a[i]=ss[i]-‘a‘+1; root=last=cnt=1; for(int i=1;i<=len;i++)add(i); scanf("%d%d",&T,&k); get_Right(T); for(int i=cnt;i>=1;i--) { int now=sa[i];sum[now]=Right[now]; for(int x=1;x<=26;x++) if(ch[now].w[x]!=0)sum[now]+=sum[ch[now].w[x]]; } if(k>sum[root])printf("-1\n"); else dfs(root); return 0; }