[BZOJ3172][TJOI2013]单词
sol
比较裸的\(AC\)自动机模板题。注意重复的单词的处理,这里使用的是并查集合并(注意也要维护大小)。较卡常。
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000005;
string s[205];
int n,l,tot,fa[205],sz[205],ch[26][N],fail[N],id[N],ans[205];
int q[N],hd,tl;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void Union(int x,int y)
{
int fx=find(x),fy=find(y);
if (fx==fy) return;
sz[fx]+=sz[fy];fa[fy]=fx;
}
void Insert(string c,int ID)
{
int l=c.length(),x=0;
for (int i=0;i<l;i++)
{
if (!ch[c[i]-'a'][x]) ch[c[i]-'a'][x]=++tot;
x=ch[c[i]-'a'][x];
}
id[x]=ID;
}
void Get_Fail()
{
for (int i=0;i<26;i++) if (ch[i][0]) q[++tl]=ch[i][0];
while (hd<tl)
{
int u=q[++hd];
for (int i=0;i<26;i++)
if (ch[i][u]) fail[ch[i][u]]=ch[i][fail[u]],q[++tl]=ch[i][u];
else ch[i][u]=ch[i][fail[u]];
}
}
void Query(string c,int k)
{
int l=c.length();
for (int i=0,x=0;i<l;i++)
{
x=ch[c[i]-'a'][x];
for (int t=x;t;t=fail[t])
ans[id[t]]+=k;
}
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>s[i],fa[i]=i,sz[i]=1;
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
if (s[i]==s[j]) Union(i,j);
for (int i=1;i<=n;i++)
if (i==find(i)) Insert(s[i],i);
Get_Fail();
for (int i=1;i<=n;i++)
if (i==find(i)) Query(s[i],sz[i]);
for (int i=1;i<=n;i++) printf("%d\n",ans[find(i)]);
return 0;
}