题意:给出n个单词,和一篇文章,即一个字符串,求其中有多少个单词出现。
TRICK: ①、重复的单词要分别计算;②、多组数据记得要清空数组,别把不该清的清了,坑死人,最后还是在某位高大佬的帮助下才发现
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<iostream>
#include<cctype>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
int t,n,l,len,tot,head=0,tail=1,tt;
char s[1000001],s1[1000001];
int f[500001][27],q[500001],fail[500001],danger[500001],vis[500001];
//-------------------
inline void f1() //建树
{
int t=0;
for(int i=1;i<=l;i++)
{ if(!f[t][s[i]-'a'])
f[t][s[i]-'a']=++tot;
t=f[t][s[i]-'a'];
}
danger[t]++;//统计一个单词的出现个数
}
//-------------------
inline void ac()
{
head=0,tail=1;
int j;
q[1]=0;
while(head^tail)
{
head++;
j=q[head];
if(j)
for(int i=0;i<26;i++)
if(f[j][i])
fail[f[j][i]]=f[fail[j]][i]; //求fail指针
for(int i=0;i<26;i++)
if(!f[j][i]) f[j][i]=f[fail[j]][i];
//优化,如果当前的点没有对应的儿子,我们就将它的儿子跳到最终会到的地方
else q[++tail]=f[j][i];
}
}
//-------------------
int main()
{
//freopen("keyword.in","r",stdin);
scanf("%d",&tt);
for(int bz=1;bz<=tt;bz++)
{
mem(f);
mem(q);
mem(fail);
mem(danger);
mem(vis);
tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
l=strlen(s+1);
f1();
}
scanf("%s",s1+1);
len=strlen(s1+1);
ac();
int now=0,tem,ans=0;
for(int i=1;i<=len;i++)
{
now=f[now][s1[i]-'a'];
tem=now;
while(tem && vis[tem]!=bz)
{
vis[tem]=bz;
ans+=danger[tem];
tem=fail[tem];
}
}
cout<<ans<<endl;
}
return 0;
}