对于一个给定长度为N的字符串,求它的第K小子串是什么。
标签:
对于一个给定长度为N的字符串,求它的第K小子串是什么。
第一行是一个仅由小写英文字母构成的字符串S
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
N<=5*10^5
后缀自动机第一题(注释见代码)
#include<iostream> #include<cstdlib> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 500005 #define maxm 1000005 using namespace std; int n,t,k; char s[maxn]; struct sam { int last,cnt; int next[maxm][26],fa[maxm],mx[maxm],val[maxm],sum[maxm],v[maxn],q[maxm]; sam(){last=++cnt;} void add(int c) { int p=last,np=last=++cnt; mx[np]=mx[p]+1;val[np]=1; while (!next[p][c]&&p) next[p][c]=np,p=fa[p]; if (!p) fa[np]=1; else { int q=next[p][c]; if (mx[p]+1==mx[q]) fa[np]=q; else { int nq=++cnt;mx[nq]=mx[p]+1; memcpy(next[nq],next[q],sizeof(next[q])); fa[nq]=fa[q];fa[np]=fa[q]=nq; while (next[p][c]==q) next[p][c]=nq,p=fa[p]; } } } void pre() { F(i,1,cnt) v[mx[i]]++; F(i,1,n) v[i]+=v[i-1]; D(i,cnt,1) q[v[mx[i]]--]=i;//q数组保存按mx排序的编号 D(i,cnt,1) { int tmp=q[i]; if (t==1) val[fa[tmp]]+=val[tmp]; else val[tmp]=1; }//val表示Right集合的大小 val[1]=0; D(i,cnt,1) { int tmp=q[i]; sum[tmp]=val[tmp]; F(j,0,25) sum[tmp]+=sum[next[tmp][j]]; }//sum表示从该点出发往下走的子串个数 } void dfs(int x,int k) { if (k<=val[x]) return;//注意返回条件 k-=val[x]; F(i,0,25) if (next[x][i]) { int tmp=next[x][i]; if (k<=sum[tmp]) { putchar(i+'a'); dfs(tmp,k); return;//注意这里的return } k-=sum[tmp]; } } }a; int main() { scanf("%s",s+1); scanf("%d%d",&t,&k); n=strlen(s+1); F(i,1,n) a.add(s[i]-'a'); a.pre(); if (k>a.sum[1]) puts("-1"); else a.dfs(1,k); return 0; }
标签:
原文地址:http://blog.csdn.net/aarongzk/article/details/51255392