AC自动机(模板) - Keywords Search - hdu 2222
题意:
给定 n 个长度不超过 50 的由小写英文字母组成的单词,以及一篇长为 m 的文章。
请问,有多少个单词在文章中出现了。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
对于每组数据,第一行一个整数 n,接下去 n 行表示 n 个单词,最后一行输入一个字符串,表示文章。
输出格式
对于每组数据,输出一个占一行的整数,表示有多少个单词在文章中出现。
数 据 范 围 : 1 ≤ n ≤ 1 0 4 , 1 ≤ m ≤ 1 0 6 数据范围:\\ 1≤n≤10^4, 1≤m≤10^6 数据范围:1≤n≤104,1≤m≤106
输入样例:
1
5
she
he
say
shr
her
yasherhs
输出样例:
3
模板代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N=1e4+10,S=55,M=1e6+10;
int n;
int tr[N*S][26],cnt[N*S],idx;
char str[M];
int ne[N*S];
queue<int> Q; ///bfs
void Insert()
{
int p=0;
for(int i=0;str[i];i++)
{
int u=str[i]-'a';
if(!tr[p][u]) tr[p][u]=++idx;
p=tr[p][u];
}
cnt[p]++;
}
void build()
{
for(int i=0;i<26;i++)
if(tr[0][i])
Q.push(tr[0][i]); //第一层:所有单词的第一个字符
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int i=0;i<26;i++)
{
int p=tr[u][i];
if(!p) tr[u][i]=tr[ne[u]][i]; //第i个儿子不存在,u的儿子就指向next的儿子
else
{
ne[p]=tr[ne[u]][i]; //儿子存在,更新next数组,同时将儿子入队
Q.push(p);
}
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(tr,0,sizeof tr);
memset(cnt,0,sizeof cnt);
memset(ne,0,sizeof ne);
idx=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",str);
Insert();
}
build();
scanf("%s",str);
int res=0;
for(int i=0,j=0;str[i];i++)
{
int u=str[i]-'a';
j=tr[j][u];
int p=j;
while(p)
{
res+=cnt[p];
cnt[p]=0;
p=ne[p];
}
}
printf("%d\n",res);
}
return 0;
}