Description
给定 (n) 个长度不超过 (50) 的由小写英文字母组成的单词准备查询,以及一篇长为 (m) 的文章,问:文中出现了多少个待查询的单词。多组数据。
Input
第一行一个整数 (T),表示数据组数;
对于每组数据,第一行一个整数 (n),接下去 (n) 行表示 (n) 个单词,最后一行输入一个字符串,表示文章。
Output
对于每组数据,输出一个数,表示文中出现了多少个待查询的单词。
Sample Input
1
5
she
he
say
shr
her
yasherhs
Sample Output
3
Hint
对于全部数据,(1le nle 10^4,1le mle 10^6)。
题解
AC自动机模板题
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<bitset>
#include<vector>
#include<iomanip>
using namespace std;
const int Size=26,Maxn=500005;
struct Trie{
int son[Maxn][Size],fail[Maxn],cnt[Maxn];
/* son[i][j]存放 父节点的下标为i 的子节点字符为j的下标
fail[i]下标为i的节点如果失配放回的下标
cnt[i]从根节点到下标为i的节点所构成的模式串的个数
*/ int id;
Trie(){id=0;}//构造函数
int Newnode()//新建一个节点
{
for(int i=0;i<Size;++i) son[id][i]=-1;
cnt[id]=0;
return id++;
}
void Init()//初始化
{
id=0,Newnode();
}
void Insert(char s[])//把模式串s插入到Trie树
{
int l=strlen(s),now=0,k;
for(int i=0;i<l;++i)
{
k=s[i]-'a';
if(son[now][k]==-1) son[now][k]=Newnode();
now=son[now][k];
}
++cnt[now];
}
queue<int> Q;
void Build()//构建Fail指针
{
while(!Q.empty()) Q.pop();
fail[0]=0;
for(int i=0;i<Size;++i)
if(son[0][i]==-1) son[0][i]=0;
else
{
fail[son[0][i]]=0;
Q.push(son[0][i]);
}
int now;
while(!Q.empty())
{
now=Q.front(); Q.pop();
for(int i=0;i<Size;++i)
if(son[now][i]==-1) son[now][i]=son[fail[now]][i];
else
{
fail[son[now][i]]=son[fail[now]][i];
Q.push(son[now][i]);
}
}
}
int Query(char s[])//文本串来匹配
{
int len=strlen(s),now=0,Res=0;
for(int i=0;i<len;++i)
{
now=son[now][s[i]-'a'];
int tmp=now;
while((tmp)&&(cnt[tmp]!=-1))
{
Res+=cnt[tmp],
cnt[tmp]=-1,
tmp=fail[tmp];
}
}
return Res;
}
}AC;
char s[Maxn+Maxn];
int main()
{
int T,n;
for(scanf("%d",&T);T;--T)
{
scanf("%d",&n);
AC.Init();
for(int i=1;i<=n;++i)
{
scanf("%s",s);
AC.Insert(s);
}
AC.Build();
scanf("%s",s);
printf("%d
",AC.Query(s));
}
return 0;
}