题目链接
给字符串求匹配数,AC自动机模板。
#include<queue>
#include<cmath>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e4+105,maxs=1e6+105;
int T;
int n,buc[maxn*55];
char s[maxs];
struct AC_zidongji
{
static const int mx_sz=26;
int rt,np,ch[maxn*55][30],val[maxn*55],cnt[maxn*55],fail[maxn*55],last[maxn*55];
void Initial()
{
rt=np=0;//这里最好是从0开始,比较利于码代码,空结点直接对应跟接电就比较好
memset(cnt,0,sizeof(cnt));
memset(ch,0,sizeof(ch));
memset(val,0,sizeof(val));
memset(fail,0,sizeof(fail));
}
int getid(char c)
{
return c-'a';
}
void ins(char *s,int k)
{
int now=rt;
for(int i=0;s[i];i++)
{
int id=getid(s[i]);
now=ch[now][id]?ch[now][id]:ch[now][id]=++np;
}
cnt[now]++;//可能多次访问同一结点
val[now]=k;
}
void getfail()//因为我们懒得存fa数组,所以我们在父亲结点计算自己点的fail
{
queue<int>q;
fail[rt]=0;
for(int p=0;p<mx_sz;p++)//必须单独考虑第一层结点咯
{
int j=ch[rt][p];
if(j){fail[j]=0;q.push(j);last[j]=0;}
}
while(!q.empty())
{
int i=q.front();q.pop();
for(int p=0;p<mx_sz;p++)//必须按照顺序加入,虽然并没有什么人会犯这个错
{
int j=ch[i][p];
if(!j){ch[i][p]=ch[fail[i]][p];continue;}
q.push(j);
int v=fail[i];
while(v && !ch[v][p])v=fail[v];
fail[j]=ch[v][p];
last[j]=val[fail[j]]?fail[j]:last[fail[j]];
}
}
}
void Count(int now)
{
if(now)
{
buc[val[now]]=cnt[now];
Count(last[now]);
}
}
void query(char *s)
{
int now=rt;
for(int i=0;s[i];i++)
{
int id=getid(s[i]);
now=ch[now][id];
val[now]?Count(now):Count(last[now]);
}
}
}AC;
void Init()
{
scanf("%d",&n);
memset(buc,0,sizeof(buc));
AC.Initial();
for(int i=1;i<=n;i++)
{
scanf("%s",s);
AC.ins(s,i);
}
AC.getfail();
}
void work()
{
scanf("%s",s);
AC.query(s);
int ans=0;
for(int i=1;i<=n;i++)ans+=buc[i];
printf("%d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
Init();
work();
}
return 0;
}