某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
这道题是一道多串匹配,所以我们可以想到AC自动机。但是作为一个字符串萌新,感觉有点难度。
难点就是s的累加,那其实如果i是j的fail,那root到i就为j的一个后缀,那i.s就可以加上j.s,那这道题就解决了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
struct node
{
int s,fail,c[27];
node()
{
s=fail=0;
memset(c,-1,sizeof(c));
}
}t[1100000];
int tot,wy[210];
char ss[1100000];
void bt(int root,int id)
{
int x=root;int len=strlen(ss+1);
for(int i=1;i<=len;i++)
{
int y=ss[i]-'a';
if(t[x].c[y]==-1)t[x].c[y]=++tot;
x=t[x].c[y];t[x].s++;
}
wy[id]=x;
}
int list[1100000];
void getfail()
{
int head=1,tail=1;
list[1]=0;
while(head<=tail)
{
int x=list[head];
for(int i=0;i<26;i++)
{
int son=t[x].c[i];
if(son==-1)continue;
if(x==0)t[son].fail=0;
else
{
int j=t[x].fail;
while(j!=0 && t[j].c[i]==-1)j=t[j].fail;
t[son].fail=max(t[j].c[i],0);
}
list[++tail]=son;
}
head++;
}
for(int i=tail;i>=1;i--)t[t[list[i]].fail].s+=t[list[i]].s;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%s",ss+1),bt(0,i);
getfail();
for(int i=1;i<=n;i++)printf("%d\n",t[wy[i]].s);
return 0;
}