BZOJ 3998: [TJOI2015]弦论 SAM
作者:互联网
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;
}
标签:ch,SAM,弦论,3998,isdigit,BZOJ,getchar 来源: https://www.cnblogs.com/G-hsm/p/11427946.html