#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
char key[1010][52],s[2000010];
int ans[1010],n;
struct ACautomata{
int next[50010][26],fail[50010],idx[50010],last[50010],num,root;
int newnode()
{
memset(next[num],0,sizeof next[num]);
idx[num]=0;
return num++;
}
void init()
{
num=0;
root=newnode();
}
void insert(char *s,int t)
{
int len=strlen(s),cur=root;
for(int i=0;i<len;++i)
{
int &tmp=next[cur][s[i]-'A'];
if(!tmp)tmp=newnode();
cur=tmp;
}
idx[cur]=t;
}
void getfail()
{
queue<int>q;
fail[root]=root;
for(int i=0;i<26;++i)
{
int u=next[root][i];
if(u)
{
fail[u]=last[u]=0;
q.push(u);
}
}
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=0;i<26;++i)
{
int u=next[cur][i];
if(u)
{
fail[u]=next[fail[cur]][i];
last[u]=idx[fail[u]]?fail[u]:last[fail[u]];
q.push(u);
}
else next[cur][i]=next[fail[cur]][i];
}
}
}
void query(char *s)
{
int len=strlen(s),cur=root;
for(int i=0;i<len;++i)
{
if(s[i]<'A'||s[i]>'Z'){cur=root;continue;}
cur=next[cur][s[i]-'A'];
int tmp=cur;
while(tmp!=root)
{
++ans[idx[tmp]];
tmp=last[tmp];
}
}
}
}ac;
int main()
{
while(~scanf("%d",&n))
{
ac.init();
memset(ans,0,sizeof ans);
memset(key,0,sizeof key);
memset(s,0,sizeof s);
for(int i=1;i<=n;++i)
{
scanf("%s",key[i]);
ac.insert(key[i],i);
}
scanf("%s",s);
ac.getfail();
ac.query(s);
for(int i=1;i<=n;++i)
if(ans[i])printf("%s: %d\n",key[i],ans[i]);
}
}
这题就是保存一个匹配串的下标,然后更新答案通过下标,++ans[下标]。
还是错了几次,第一次是字符串大小开小了。第二次是原串中没有一个可以匹配的时候要continue,之前要把当前的节点返回到根。这个很显然但是我忘记了。