您的位置:首页 > 其它

bzoj 3998: [TJOI2015]弦论

2015-07-01 21:38 393 查看

Description

对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

Output

输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

aabc

0 3

Sample Output

aab

HINT

N<=5*10^5

T<2

K<=10^9

建出后缀自动机,然后在后缀自动机上跑一下就可以。
维护后面有几种情况
切记虚点处置为0。。
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
int T;
int lx;
struct sam
{
int son[1000005][26],pre[1000005],step[1000005];
int v[1000005],q[1000005];
int s[1000005],sum[1000005];
int last,tot;
sam()
{
last=1;
tot=1;
}
inline void push_back(int v)
{
tot++;
step[tot]=v;
}
inline void extend(int x)
{
push_back(step[last]+1);
int p=last,np=tot;s[np]=1;
while(son[p][x]==0&&p!=0)
{
son[p][x]=np;
p=pre[p];
}
if(p==0)
pre[np]=1;
else
{
int q=son[p][x];
if(step[q]!=step[p]+1)
{
push_back(step[p]+1);
//tot++;
int nq=tot;
int i;
for(i=0;i<=25;i++)
son[nq][i]=son[q][i];
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
while(son[p][x]==q)
{
son[p][x]=nq;
p=pre[p];
}
}
else
pre[np]=q;
}
last=np;
}
inline void build()
{
string x;
cin>>x;
lx=x.size();
int i;
for(i=0;i<=lx-1;i++)
extend(x[i]-'a');
}
inline void prep()
{
int i,j;
for(i=1;i<=tot;i++)
v[step[i]]++;
for(i=1;i<=tot;i++)
v[i]+=v[i-1];
for(i=tot;i>=1;i--)
q[v[step[i]]--]=i;
// for(i=1;i<=tot;i++)
// s[i]=1;
for(i=tot;i>=1;i--)
{
if(T==1)
s[pre[q[i]]]+=s[q[i]];
else
s[q[i]]=1;
}
s[1]=0;
for(i=tot;i>=1;i--)
{
sum[q[i]]+=s[q[i]];
for(j=0;j<=25;j++)
sum[q[i]]+=sum[son[q[i]][j]];
}
}
inline void dfs(int d,int k)
{
if(k<=s[d])
return ;
k-=s[d];
int i;
for(i=0;i<=25;i++)
{
int t=son[d][i];
if(t!=0)
{
if(k<=sum[t])
{
printf("%c",i+'a');
dfs(t,k);
return ;
}
k-=sum[t];
}
}
}
}sam;
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
sam.build();
int k;
scanf("%d%d",&T,&k);
sam.prep();
if(k>sam.sum[1])
printf("-1\n");
else
{
sam.dfs(1,k);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: