bzoj 3473: 字串 (字尾自動機)
阿新 • • 發佈:2019-01-28
題目描述
傳送門
題目大意:給定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");
}