1. 程式人生 > >bzoj 3473: 字串 (字尾自動機)

bzoj 3473: 字串 (字尾自動機)

題目描述

傳送門

題目大意:給定n個字串,詢問每個字串有多少子串(不包括空串)是所有n個字串中至少k個字串的子串?

題解

同bzoj3277

程式碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 200003
#define LL long long
using namespace std;
int tot,n,k,point[N],nxt[N],v1[N],ch[N][30],fa[N],c[N];
int v[N],pos[N],l[N],mark[N],cnt,root,last,np,q,p,nq,head[N],next[N];
char
s[N]; LL ct[N],ans[N]; void add(int x,int y) { tot++; nxt[tot]=point[x]; point[x]=tot; v1[tot]=y; } void extend(int x,int col) { int c=s[x]-'a'+1; np=++cnt; p=last; last=np; l[np]=l[p]+1; for (;!ch[p][c]&&p;p=fa[p]) ch[p][c]=np; if (!p) fa[np]=root; else { q=ch[p][c]; if
(l[p]+1==l[q]) fa[np]=q; else { nq=++cnt; l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[nq])); fa[nq]=fa[q]; mark[nq]=mark[q]; ct[nq]=ct[q]; fa[q]=fa[np]=nq; for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; } } add(col,np); for
(;np;np=fa[np]) if (mark[np]!=col) { mark[np]=col; ct[np]++; } else break; } void build(int x,int y) { tot++; next[tot]=head[x]; head[x]=tot; v[tot]=y; } void dfs(int x) { for (int i=head[x];i;i=next[i]){ ans[v[i]]+=ans[x]; dfs(v[i]); } } int main() { freopen("a.in","r",stdin); scanf("%d%d",&n,&k); root=++cnt; for (int i=1;i<=n;i++) { scanf("%s",s+1); int len=strlen(s+1); last=root; for (int j=1;j<=len;j++) extend(j,i); } for (int i=1;i<=cnt;i++) v[l[i]]++; for (int i=1;i<=cnt;i++) v[i]+=v[i-1]; for (int i=1;i<=cnt;i++) pos[v[l[i]]--]=i; tot=0; for (int i=1;i<=cnt;i++) { int t=pos[i]; build(fa[t],t); ans[t]=(ct[t]>=k?l[t]-l[fa[t]]:0); } c[1]=0; dfs(1); for (int i=1;i<=n;i++) { LL sum=0; for (int j=point[i];j;j=nxt[j]) sum+=ans[v1[j]]; printf("%lld ",sum); } printf("\n"); }