来源:HDU2222
AC自动机,参考了kuangbin模板,具体的理解在注释里
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 500010;
const int ALTN = 26;
struct Trie{//将整个字典树做成一个AC自动机
int nxt[MAXN][ALTN]; //字典树,nxt[rt][i]表示rt为根的节点中第i个指针
int fail[MAXN]; //失败指针
int en[MAXN];
int root,L; //头指针
int newnode(){ //构造函数,但是这里并没有按照构造函数来处理
for(int i=0;i<ALTN;i++)
{
nxt[L][i] = -1;
}
en[L++] = 0;
return L-1;
}
void ini(){
L = 0; //初始化
root = newnode(); //root下面建立第一个指针
}
void insert(char buff[]){ //构造一个字典树
int len = strlen(buff);
int now = root;
for(int i=0;i<len;i++){
if(nxt[now][buff[i]-'a']==-1)//如果还没有这个节点
{
nxt[now][buff[i]-'a'] = newnode();
}
now = nxt[now][buff[i]-'a'];//向下走一格
}
en[now]++; //记录结尾信息,类比字典树
}
void build(){ //建一棵AC自动机
queue<int>Q;
fail[root] = root;
for(int i=0;i<26;i++){
if(nxt[root][i]==-1) nxt[root][i] = root;
else{
fail[nxt[root][i]] = root;
Q.push(nxt[root][i]);
}
}
//以上,处理了第一个字符的情况
while(!Q.empty()){
int now = Q.front();
Q.pop();
for(int i=0;i<ALTN;i++){
if(nxt[now][i]==-1) nxt[now][i] = nxt[fail[now]][i];
//表示并不存在当前位置,从而赋值为父节点都失败指针
else {
fail[nxt[now][i]] = nxt[fail[now]][i];
Q.push(nxt[now][i]);
}
//存在此节点,或者说这个节点已经被赋值到失败的情况
//当前的fail指针指向我的指向
//加入这个节点
}
}
}
int query(char buff[]){
int len = strlen(buff);
int now = root;
int res = 0;
for(int i=0;i<len;i++){
now = nxt[now][buff[i]-'a'];
int temp = now; //temp指针
while(temp!=root){
res+=en[temp]; //出现了,那么加上这个所有单词
en[temp]=0;
temp=fail[temp];
}
}
return res;
}
};
char buff[1000010];
Trie Ac;//kuangbin的风格是这样,将整个结构体做成一个AC自动机
//主函数,输入输出流程
int main(){
int T;
int n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
Ac.ini();
for(int i=0;i<n;i++){
scanf("%s",buff);
Ac.insert(buff);
}
Ac.build();
scanf("%s",buff);
printf("%d\n",Ac.query(buff));
}
return 0;
}