BZOJ3998:[TJOI2015]弦论——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3998
https://www.luogu.org/problemnew/show/P3975
对于一个给定长度为N的字符串,求它的第K小子串是什么。
后缀自动机,对l排序然后从后往前推size和sum数组(貌似也可以叫拓扑?)。
size:当前状态的字符串个数(贡献)。
sum:以当前状态为起点之后的满足要求的字符串个数。
#include<cstdio> #include<iostream> #include<queue> #include<cstring> #include<algorithm> #include<cctype> using namespace std; typedef long long ll; const int N=1e6+5; struct tree{ int a[26],fa,l; }tr[N]; char s[N]; int last,cnt,t,k; ll a[N],w[N],size[N],sum[N]; inline void insert(int c){ int p=last,np=++cnt; last=np;tr[np].l=tr[p].l+1; for(;p&&!tr[p].a[c];p=tr[p].fa)tr[p].a[c]=np; if(!p)tr[np].fa=1; else{ int q=tr[p].a[c]; if(tr[p].l+1==tr[q].l)tr[np].fa=q; else{ int nq=++cnt;tr[nq].l=tr[p].l+1; memcpy(tr[nq].a,tr[q].a,sizeof(tr[q].a)); tr[nq].fa=tr[q].fa;tr[q].fa=tr[np].fa=nq; for(;p&&tr[p].a[c]==q;p=tr[p].fa)tr[p].a[c]=nq; } } size[np]=1; } int main(){ scanf("%s%d%d",s,&t,&k); int len=strlen(s); last=cnt=1; for(int i=0;i<len;i++)insert(s[i]-'a'); for(int i=1;i<=cnt;i++)w[tr[i].l]++; for(int i=1;i<=len;i++)w[i]+=w[i-1]; for(int i=1;i<=cnt;i++)a[w[tr[i].l]--]=i; for(int i=cnt;i>=1;i--){ if(t)size[tr[a[i]].fa]+=size[a[i]]; else size[a[i]]=1; } size[1]=0; for(int i=cnt;i>=1;i--){ sum[a[i]]=size[a[i]]; for(int j=0;j<26;j++) if(tr[a[i]].a[j]) sum[a[i]]+=sum[tr[a[i]].a[j]]; } if(k>sum[1])puts("-1"); else{ int now=1; while(k>size[now]){ k-=size[now]; int i; for(int i=0;i<26;i++){ if(k>sum[tr[now].a[i]]) k-=sum[tr[now].a[i]]; else{ now=tr[now].a[i]; putchar(i+'a'); break; } } } puts(""); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++