标签:register 数字 一个 第k小 tput log scanf rip void
对于一个给定长度为N的字符串,求它的第K小子串是什么。
第一行是一个仅由小写英文字母构成的字符串S
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
N<=5*10^5
正解:后缀自动机。
我们可以使用后缀自动机来求出每一个后缀,那么可以知道,一个字符串的出现次数就是它的$right$集合大小,也就是它在后缀自动机的$parent$树上的子树大小。
那么如果$T=1$,就把一个点的$sz$统计成它的$parent$子树,否则它的$sz$就是$1$,然后我们贪心地找出第$k$小子串就行了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define N (1000010) 6 7 using namespace std; 8 9 int ch[N][26],l[N],fa[N],sz[N],sum[N],c[N],id[N],n,t,k,la,tot,len; 10 char s[N]; 11 12 il void add(RG int c){ 13 RG int p=la,np=++tot; la=np,l[np]=l[p]+1,sz[np]=1; 14 for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np; 15 if (!p){ fa[np]=1; return; } RG int q=ch[p][c]; 16 if (l[q]==l[p]+1) fa[np]=q; else{ 17 RG int nq=++tot; l[nq]=l[p]+1; 18 fa[nq]=fa[q],fa[q]=fa[np]=nq; 19 memcpy(ch[nq],ch[q],sizeof(ch[q])); 20 for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 21 } 22 return; 23 } 24 25 il void dfs(RG int x,RG int k){ 26 if (k<=sz[x]) return; RG int c=sz[x]; 27 for (RG int i=0;i<26;++i) 28 if (k<=c+sum[ch[x][i]]){ 29 putchar(‘a‘+i); 30 return dfs(ch[x][i],k-c); 31 } else c+=sum[ch[x][i]]; 32 return; 33 } 34 35 int main(){ 36 #ifndef ONLINE_JUDGE 37 freopen("kth.in","r",stdin); 38 freopen("kth.out","w",stdout); 39 #endif 40 scanf("%s",s+1),len=strlen(s+1),cin>>t>>k,tot=la=1; 41 for (RG int i=1;i<=len;++i) add(s[i]-‘a‘); 42 for (RG int i=1;i<=tot;++i) ++c[l[i]]; 43 for (RG int i=1;i<=tot;++i) c[i]+=c[i-1]; 44 for (RG int i=1;i<=tot;++i) id[c[l[i]]--]=i; 45 if (t) for (RG int i=tot;i;--i) sz[fa[id[i]]]+=sz[id[i]]; 46 else for (RG int i=tot;i;--i) sz[id[i]]=1; sz[1]=0; 47 for (RG int i=tot;i;--i){ 48 sum[id[i]]=sz[id[i]]; 49 for (RG int j=0;j<26;++j) 50 sum[id[i]]+=sum[ch[id[i]][j]]; 51 } 52 if (sum[1]<k) puts("-1"); else dfs(1,k); return 0; 53 }
标签:register 数字 一个 第k小 tput log scanf rip void
原文地址:http://www.cnblogs.com/wfj2048/p/7630221.html