【bzoj3998】[TJOI2015]弦论 后缀自动机

来源:互联网 发布:灵魂摆渡3风华绝代知乎 编辑:程序博客网 时间:2024/06/04 18:01

非常好的一道裸题

T=1

每个节点的出现次数=它的right集合大小

初始时,每加入一个节点,它对应的right集合大小就为1

T=0

每个节点算一次,即把right集合大小强制变为1

对深度计数排序后,节点i对fa[i]产生贡献

计算出size[i]表示包含节点i在内,所有的能转移到的子串的出现次数之和

注意:不能按bfs序处理size,因为计算size时,还没计算完cnt,类似拓扑图的bfs和拓扑排序的区别

即后缀自动机的节点按mx排序后,是拓扑序


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#define maxn 500010using namespace std;int ch[maxn*2][26],mx[maxn*2],size[maxn*2],fa[maxn*2],cnt[maxn*2],q[maxn*2],v[maxn*2];int n,m,tot=1,T,last=1;bool vis[2*maxn];char s[maxn];long long k;void insert(int x){int p=last,np=last=++tot;mx[np]=mx[p]+1;cnt[np]=1;while (p && !ch[p][x]) ch[p][x]=np,p=fa[p];if (!p) fa[np]=1;else{int q=ch[p][x];if (mx[q]==mx[p]+1) fa[np]=q;else{int nq=++tot;mx[nq]=mx[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[q]));fa[nq]=fa[q];fa[np]=fa[q]=nq;while (p && ch[p][x]==q) ch[p][x]=nq,p=fa[p];}}}void bfs(){for (int i=1;i<=tot;i++) v[mx[i]]++;for (int i=1;i<=n;i++) v[i]+=v[i-1];for (int i=tot;i>=1;i--) q[v[mx[i]]--]=i;for (int i=tot;i>=1;i--){int x=q[i];if (T==0) cnt[x]=1; else cnt[fa[x]]+=cnt[x];if (x==1) cnt[x]=0;size[x]=cnt[x];for (int j=0;j<26;j++) if (ch[x][j]) size[x]+=size[ch[x][j]];}}void dfs(int x,long long k){if (k<=cnt[x]) return;k-=cnt[x];for (int i=0;i<26;i++)  if (ch[x][i])  {  if (k<=size[ch[x][i]])  {  printf("%c",i+'a');  dfs(ch[x][i],k);  return;  }k-=size[ch[x][i]];  }}int main(){scanf("%s",s+1);n=strlen(s+1);for (int i=1;i<=n;i++) insert(s[i]-'a');scanf("%d%lld",&T,&k);bfs();if (k>size[1]) printf("-1\n");else dfs(1,k);return 0;}


0 0
原创粉丝点击