某人讀論文,一篇論文是由許多單詞組成。但他發現一個單詞會在論文中出現很多次,現在想知道每個單詞分別在論文中出現多少次。
這道題是一道多串匹配,所以我們可以想到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;
}