挺裸的一个AC自动机的题,但是网上的题解基本都有些问题,主要有两个,一个是在沿fail指针向上更新时很多人都是遇到节点的count为0时直接跳出的,这没有任何道理吧。。。还有一个就是就算不直接跳出来遇到极限数据这样做也会TLE,我们应该先跑一边自动机,跑的时候不要沿fail指针向上更新,我们最后才按节点的拓扑序一次统计。不过这题数据太弱了怎么做都能过就是了。。。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#define N 50500
#define Max 27
using namespace std;
struct node
{
int count,num;
node *next[Max],*fail;
} tree[N],*root;
int cnt;
int ans[N];
node* newnode()
{
for(int i = 0; i<Max; i++)tree[cnt].next[i] = NULL;
tree[cnt].fail=NULL;
tree[cnt].count = tree[cnt].num = 0;
return &tree[cnt++];
}
void insert(char *str,int x)
{
int i=0,s;
node *t=root;
while(str[i])
{
s=str[i]-'A';
if(t->next[s]==NULL)
t->next[s]=newnode();
t=t->next[s];
i++;
}
t->count = x;
}
node *q[N];
int head,tail;
void build_ac_automation()
{
head = tail = 0;
node *tmp=root;
q[tail++] = tmp;
while(head<tail)
{
tmp=q[head++];
for(int i=0; i<Max; i++)
if(tmp->next[i]==NULL)
{
if(tmp==root)tmp->next[i]=root;
else tmp->next[i]=tmp->fail->next[i];
}
else
{
if(tmp==root)tmp->next[i]->fail=root;
else tmp->next[i]->fail=tmp->fail->next[i];
q[tail++] = tmp->next[i];
}
}
}
char word[N][55];
char s[2000005];
int main()
{
int n,i,j;
while(scanf("%d",&n)!=EOF)
{
cnt = 0;
root = newnode();
for(i = 1; i<=n; i++)
{
scanf("%s",word[i]);
insert(word[i],i);
}
build_ac_automation();
memset(ans,0,sizeof(ans));
scanf("%s",s);
int len = strlen(s);
node *tmp = root;
for(int i = 0; i<len; i++)
{
int v = s[i]-'A';
if(v<0||v>25)v = 26;
while(tmp&&tmp->next[v] == NULL)tmp = tmp->fail;
if(tmp == NULL)tmp = root;
else tmp = tmp->next[v];
tmp->num++;
}
for(i = tail-1;i;i--)
{
ans[q[i]->count]=q[i]->num;
q[i]->fail->num+=q[i]->num;
}
for(i = 1; i<=n; i++)
if(ans[i])printf("%s: %d\n",word[i],ans[i]);
}
return 0;
}