/*
-------------AC自动机------------
解决多模式字符串匹配问题
利用模式字符串组来构建字典树(注:这里不同于字典树!!!)
通过查询便可得出其中模式串出现的个数
HDU 2222:AC自动机模板题
有坑
要加上这行代码:memset(trie[0],0,sizeof(trie[0]));
否则疯狂TLE
*/
#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<cmath>
using namespace std;
#define ll long long
#define pi acos(-1)
const int maxn = 1e6+5;
int trie[maxn][26]; //字典树
int color[maxn]; //标记终点
int id; //当前字典树中有几个节点
int fail[maxn]; //匹配失败时的跳转指针
char ss[10000005];
inline void insert(char *s) //将字符串s插入字典树
{
int len = strlen(s);
int p = 0; //从0节点开始
for(int i=0;i<len;++i)
{
int c = s[i] - 'a';
if(!trie[p][c]) //没有边,就加边
trie[p][c] = ++id;
p = trie[p][c];
}
++color[p];
}
inline void getfail() //利用BFS获取fail数组
{
queue<int>q; //利用BFS获取fail数组
for(int i=0;i<26;++i) //将第二层所有出现了的字母扔进队列
if(trie[0][i])
{
fail[trie[0][i]] = 0;
q.push(trie[0][i]);
}
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i=0;i<26;++i)
{
if(trie[u][i])
{
fail[trie[u][i]] = trie[fail[u]][i];
q.push(trie[u][i]);
}
else
trie[u][i] = trie[fail[u]][i];
}
}
}
inline int search(char *s) //模式串匹配--只能查出模式串是否出现
{
int len = strlen(s);
int ans = 0;
int p = 0;
for(int i=0;i<len;++i)
{
int c = s[i] - 'a';
p = trie[p][c];
for(int j=p;j&&color[j]!=-1;j=fail[j])
{
//一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过
ans += color[j];
color[j] = -1; //将遍历过后的节点标记,防止重复计算
}
}
return ans;
}
signed main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(fail,0,sizeof(fail));
memset(color,0,sizeof(color));
memset(trie[0],0,sizeof(trie[0]));
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%s",ss);
insert(ss);
}
getfail();
scanf("%s",ss);
printf("%d\n",search(ss));
}
return 0;
}
HDU 2222 [AC自动机] --by二汪
最新推荐文章于 2023-02-28 21:10:35 发布