【BZOJ 3277】串 广义后缀自动机

来源:互联网 发布:算法设计 编辑:程序博客网 时间:2024/05/18 19:46

判断一个串是否在至少k个字符串里面的方法后3473一样,每添加一个新的字符就沿fail链更新。

剩下的问题就只是剩下了,每增加一个新的字符,共多出现了多少个新的字符串,如果不要求重复,那么很显然就是len[u]-len[fail[u]],这里重复的字串也需要加入答案所以只用沿fail链dfs一下,sum[u]=fail链上所有的坏和就好了

#include<cstdio>#include<cstring>#include<iostream>#define maxn 200021#include<vector>#define LL long longusing namespace std;int len[maxn],n,K,son[maxn][26],sz[maxn];LL sum[maxn];int fail[maxn],now,bg[maxn],bl[maxn],last=1,tot=1,rt=1;char s[maxn];vector<int>g[maxn],e[maxn];void insert(int c){int p=last,np=++tot,q,nq;last=np;len[np]=len[p]+1;while(p&&!son[p][c])son[p][c]=np,p=fail[p];if(!p)fail[np]=rt;else{q=son[p][c];if(len[q]==len[p]+1)fail[np]=q;else{nq=++tot;len[nq]=len[p]+1;sz[nq]=sz[q],fail[nq]=fail[q],bl[nq]=bl[q];memcpy(son[nq],son[q],sizeof(son[nq]));fail[np]=fail[q]=nq;while(p&&son[p][c]==q)son[p][c]=nq,p=fail[p];}}g[now].push_back(np);while(np&&bl[np]!=now){sz[np]++;bl[np]=now;np=fail[np];}}void dfs(int u){for(int v,i=0;i<e[u].size();i++){v=e[u][i];sum[v]+=sum[u];dfs(v);}}int main(){scanf("%d%d",&n,&K);for(int l,i=1;i<=n;i++){last=rt;scanf("%s",s+bg[i]);l=strlen(s+bg[i]);bg[i+1]=bg[i]+l;now=i;for(int j=bg[i];j<bg[i+1];j++)insert(s[j]-'a');}for(int i=tot;i>1;i--){e[fail[i]].push_back(i);if(sz[i]>=K)sum[i]=len[i]-len[fail[i]];}sum[1]=0;dfs(1);for(int i=1;i<=n;i++){LL ans=0;for(int u,j=0;j<g[i].size();j++){u=g[i][j];ans+=sum[u];}printf("%lld ",ans);}return 0;}


0 0