#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
#include<climits>
using namespace std;
inline int read()
{
char ls=getchar();for (;ls<'0'||ls>'9';ls=getchar());
int x=0;for (;ls>='0'&&ls<='9';ls=getchar()) x=x*10+ls-'0';
return x;
}
int n,m,ans,sz;
int a[500001][30];
int z[500001],d[500001];
char s[1000001];
bool bj[500001];
queue<int>q;
int main()
{
n=read();
for(int i=1;i<=n;++i)
{
sz=1;
for(int j=1;j<=29;++j)
a[0][j]=1;
m=read();
for(int j=1;j<=m;++j)//构造trie树的边集
{
scanf("%s",&s);
int k=1;int l=strlen(s)-1;
for(int h=0;h<=l;++h)
{
int t=s[h]-'a'+1;
if(a[k][t])k=a[k][t];//向后寻找
else k=a[k][t]=++sz;//没有找到
}
++d[k];//该点为一个字符串的结尾
}
z[1]=0;
q.push(1);
while(!q.empty())//用队列构造fail数组
{
int k=q.front();
q.pop();
for(int j=1;j<=26;++j)
if(a[k][j])
{
int l=z[k];
while(!a[l][j])l=z[l];//不停寻找fail的位置
z[a[k][j]]=a[l][j];
q.push(a[k][j]);
}
}
scanf("%s",&s);
int l=strlen(s)-1;
ans=0;
int k=1;
for(int i=0;i<=l;i++)
{
bj[k]=1;
int t=s[i]-'a'+1;
while(!a[k][t])k=z[k];//沿着fail指针寻找
k=a[k][t];
if(!bj[k])//如果没有标记,检查可能出现的字符串
for(int j=k;j;j=z[j])
{
ans+=d[j];
d[j]=0;//防止再次被检查计数
if(bj[k]==1)
break;
}
}
cout<<ans<<endl;
for(int j=1;j<=sz;++j)
{
z[j]=d[j]=bj[j]=0;
for(int h=1;h<=26;++h)
a[j][h]=0;
}
}
return 0;
}
HDU2222 AC自动机模板
最新推荐文章于 2024-06-16 22:31:26 发布