注意:一个模式串可以被计算多次。
分析:每个节点记录fail树上到根的路径和。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
const int maxn=1e6+7;
using namespace std;
int n,cnt;
char s[maxn];
struct trie{
int s,fail;
int vis[26];
}t[maxn];
void add(char *s)
{
int len=strlen(s);
int now=0;
for (int i=0;i<len;i++)
{
if (!t[now].vis[s[i]-'a'])
{
t[now].vis[s[i]-'a']=++cnt;
}
now=t[now].vis[s[i]-'a'];
}
t[now].s++;
}
void getfail()
{
queue <int> q;
while (!q.empty()) q.pop();
for (int i=0;i<26;i++)
{
if (t[0].vis[i])
{
t[t[0].vis[i]].fail=0;
q.push(t[0].vis[i]);
}
}
while (!q.empty())
{
int u=q.front();
q.pop();
for (int i=0;i<26;i++)
{
if (t[u].vis[i])
{
t[t[u].vis[i]].fail=t[t[u].fail].vis[i];
q.push(t[u].vis[i]);
t[t[u].vis[i]].s+=t[t[t[u].vis[i]].fail].s;
}
else
{
t[u].vis[i]=t[t[u].fail].vis[i];
}
}
}
}
void find(char *s)
{
int now=0;
int len=strlen(s);
int ans=0;
for (int i=0;i<len;i++)
{
now=t[now].vis[s[i]-'a'];
ans+=t[now].s;
}
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
memset(t,0,sizeof(t));
cnt=0;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
add(s);
}
getfail();
scanf("%s",s);
find(s);
}
}