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查询。
题意
给出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; }
相关文章推荐
- 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )
- bzoj3998 [TJOI2015]弦论(SAM)
- bzoj3998 [TJOI2015]弦论(SAM)
- 【TJOI2015】【BZOJ3998】弦论
- bzoj3998 TJOI2015 弦论
- [BZOJ3998][TJOI2015]弦论(后缀自动机)
- bzoj3998 [TJOI2015]弦论
- [BZOJ3998]TJOI2015弦论|后缀自动机
- 【bzoj3998】[TJOI2015]弦论
- [bzoj3998][TJOI2015]弦论-后缀自动机
- bzoj 3998: [TJOI2015]弦论(后缀自动机)
- bzoj3998 [TJOI2015]弦论
- bzoj 3998 [TJOI2015]弦论
- bzoj 3998 [TJOI2015]弦论
- ●BZOJ 3998 [TJOI2015]弦论
- [BZOJ3998] [TJOI2015] 弦论 - 后缀自动机
- BZOJ3998: [TJOI2015]弦论
- BZOJ3998 TJOI2015弦论(后缀数组+二分答案)
- BZOJ 3998 [TJOI2015]弦论
- 【bzoj3998】[TJOI2015]弦论 后缀自动机