您的位置:首页 > 其它

BZOJ3998 [TJOI2015]弦论 (SAM)

2018-03-18 16:36 483 查看
题目链接 BZOJ3998

题意

给出5e5长度的字符串,输出第k小子串。当t=0时相同子串算一个,t=1相同子串算多个。

思路

后缀自动机经典题,还是对Right集合性质的利用。知道从根走到每个节点都代表一个S子串,所有节点不重不漏的表示出S的所有子串。t=0时直接把每个节点的cnt=1,然后按step拓扑倒序把每个节点儿子所能表示的子串数量统计出来,再从根dfs查询。t=1时把主串节点的cnt=1,按step拓扑倒序将数量向前累加到pre节点,实际上是统计每个节点的|Right|,再从根dfs查询。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
#include <iostream>
#include <stack>
#include <set>
#include <map>
#include <string>
#define pi acos(-1.0)
using namespace std;

const int MAX=1e6+5;
int t,k;
int cnt[MAX],topo[MAX];
long long rt[MAX],sum[MAX];
char str[MAX];
int son[MAX][26],pre[MAX],step[MAX],last,total;

inline void push_back(int v){
step[++total]=v;
}

void init(){
total=last=0;
memset(son,0,sizeof(son));
memset(pre,0,sizeof(pre));
memset(step,0,sizeof(step));
pre[0]=-1;
}

void Extend(int ch){
push_back(step[last]+1);
int p=last,np=total;
rt[np]=1;
for(;!son[p][ch]&&p!=-1;p=pre[p])
son[p][ch]=np;
if(p==-1)
pre[np]=0;
else{
int q=son[p][ch];
if(step[q]!=step[p]+1){
push_back(step[p]+1);
int nq=total;
memcpy(son[nq],son[q],sizeof(son[q]));
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
for(;son[p][ch]==q;p=pre[p])
son[p][ch]=nq;
}
else
pre[np]=q;
}
last=np;
}

void solve(int x,int k){
int i;

if(k<=rt[x])    //不继续向后
return ;
k-=rt[x];    //减去以自己为子串终点的数量
for(i=0;i<26;i++)
if(son[x][i]){
if(k<=sum[son[x][i]]){
putchar(i+'a');
solve(son[x][i],k);
break;
}
k-=sum[son[x][i]];
}
}

int main(){
int i,j,len;

scanf("%s%d%d",&str,&t,&k);
len=strlen(str);
init();
for(i=0;i<len;i++)
Extend(str[i]-'a');
for(i=1;i<=total;i++)
cnt[step[i]]++;
for(i=1;i<=len;i++)
cnt[i]+=cnt[i-1];
for(i=total;i>=1;i--)
topo[cnt[step[i]]--]=i;
for(i=total;i>=1;i--){
if(t)
rt[pre[topo[i]]]+=rt[topo[i]];
else
rt[topo[i]]=1;
}
for(i=total;i>=1;i--){
sum[topo[i]]=rt[topo[i]];
for(j=0;j<26;j++)
sum[topo[i]]+=sum[son[topo[i]][j]];
}
for(j=0;j<26;j++)
if(son[0][j])
sum[0]+=sum[son[0][j]];
rt[0]=0;
if(sum[0]<k)
printf("-1");
else
solve(0,k);
putchar('\n');

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: