AC自动机:简单版
询问每个字符串是否出现过
为了压缩时间,我们当碰到一个ed结点的时候,
如果该结点没有访问过,我们就按照fail跳一遍
如果该结点之前统计过,我们就不用顺着fail指针再统计了
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1000005;
int n,ch[N][26],tot=0,word[N];
char s[N],w[N];
bool ed[N];
int Q[N],tou,wei,cnt[N],fail[N];
void build(int bh)
{
int len=strlen(w);
int now=0;
for (int i=0;i<len;i++)
{
int x=w[i]-'a';
if (!ch[now][x]) ch[now][x]=++tot;
now=ch[now][x];
}
ed[now]=1;
word[bh]=now;
}
void makefail()
{
tou=wei=0;
for (int i=0;i<26;i++)
if (ch[0][i])
Q[++wei]=ch[0][i];
while (tou<wei)
{
int now=Q[++tou];
for (int i=0;i<26;i++)
{
if (!ch[now][i])
{
ch[now][i]=ch[fail[now]][i];
continue;
}
Q[++wei]=ch[now][i];
fail[ch[now][i]]=ch[fail[now]][i];
}
}
}
void solve()
{
memset(cnt,0,sizeof(cnt));
int len=strlen(s);
int now=0,ans=0;
for (int i=0;i<len;i++)
{
int x=s[i]-'a';
while (now&&!ch[now][x]) now=fail[now];
now=ch[now][x];
if (ed[now]&&cnt[now]==0) //cnt=0 第一次访问
{
cnt[now]++;
int f=now;
while (f&&cnt[f]==0)
{
f=fail[f];
cnt[f]++;
}
}
}
for (int i=1;i<=n;i++) if (cnt[word[i]]) ans++;
printf("%d",ans);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",w);
build(i);
}
makefail();
scanf("%s",s);
solve();
return 0;
}