title
Description
对于一个给定的长度为 \(n\) 的字符串,求出它的第 \(k\) 小子串是什么。
analysis
建出 \(SAM\) 求 \(K\) 大。
\(T=0\) 除了根以外的状态都代表 \(1\) 个串;
\(T=1\) 每个状态 \(fail\) 子树结束结点个数即为串的个数。
code
#include<bits/stdc++.h> using namespace std; const int maxn=5e5+10; char buf[1<<15],*fs,*ft; inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; } template<typename T>inline void read(T &x) { x=0; T f=1, ch=getchar(); while (!isdigit(ch) && ch^'-') ch=getchar(); if (ch=='-') f=-1, ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar(); x*=f; } int T,K,n; struct SuffixAutoMaton { int last,cnt; int ch[maxn<<1][26],fa[maxn<<1],l[maxn<<1];//数据范围不计算清楚真是害死人 inline void extend(int c) { int p=last,np=++cnt; last=cnt; l[np]=l[p]+1; for ( ; p && !ch[p][c]; p=fa[p]) ch[p][c]=np; if (!p) fa[np]=1; else { int q=ch[p][c]; if (l[p]+1==l[q]) fa[np]=q; else { int nq=++cnt; l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; for ( ; ch[p][c]==q; p=fa[p]) ch[p][c]=nq; } } siz[np]=1; } int c[maxn],a[maxn<<1],siz[maxn<<1],sum[maxn<<1];//数据范围不计算清楚真是害死人 inline void calc() { for (int i=1; i<=cnt; ++i) ++c[l[i]]; for (int i=1; i<=n; ++i) c[i]+=c[i-1];//只需要计算出这个字符串实际长度的前缀即可 for (int i=cnt; i; --i) a[c[l[i]]--]=i;//倒序搞 for (int i=cnt; i; --i)//从小到大枚举,实际上在模拟parent树的DFS { int p=a[i]; if (T==1) siz[fa[p]]+=siz[p]; else siz[p]=1; } siz[1]=0; for (int i=cnt; i; --i) { int p=a[i]; sum[p]=siz[p]; for (int j=0; j<26; ++j) sum[p]+=sum[ch[p][j]]; } } inline void dfs(int x,int K) { if (K<=siz[x]) return ; K-=siz[x]; for (int i=0; i<26; ++i) if (int p=ch[x][i]) { if (K<=sum[p]) { putchar(i+'a'); dfs(p,K); return ; } K-=sum[p]; } } } SAM; char s[maxn]; int main() { scanf("%s",s+1); n=strlen(s+1);SAM.cnt=SAM.last=1;//1为跟,表示空串 read(T);read(K); for (int i=1; i<=n; ++i) SAM.extend(s[i]-'a'); SAM.calc(); if (K>SAM.sum[1]) puts("-1"); else SAM.dfs(1,K),puts(""); return 0; }
来源:博客园
作者:G-hsm
链接:https://www.cnblogs.com/G-hsm/p/11427946.html