题意:
题目的意思是给你一些模板串,问你这些模板串在主串中出现的数量。
tag:AC自动机
分析:直接使用AC自动机模板求解, 注意如果不加mark数组会超时, mark数组保证已经统计过的顶点不需要再统计。
#include <algorithm>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cstdio>
using namespace std;
const int N = 500000 + 100;
const int maxn = 1000000 + 100;
const int Root = 0;
struct Trie{
char data;
int cnt; //结点所对应单词的数量
int fail; //fail失败指针
int next[26];
}tree[N];
int tot;
void init(int p, char a) {
tree[p].data = a;
tree[p].cnt = 0;
tree[p].fail = -1;
memset(tree[p].next, -1, sizeof(tree[p].next));
}
void Insert(char s[]) {
int p = Root;
for(int i=0; s[i]; i++) {
int t = s[i] - 'a';
if(tree[p].next[t] == -1) { //申请内存
++tot; init(tot, s[i]);
tree[p].next[t] = tot;
}
p = tree[p].next[t];
}
tree[p].cnt++;
}
void get_fail() {
queue<int> que;
tree[Root].fail = -1;
que.push(Root);
while(!que.empty()) {
int k = que.front(); que.pop();
for(int j=0; j<26; j++) {
int son = tree[k].next[j];
if(son != -1) {
if(k == Root) tree[son].fail = Root;
else {
int t = tree[k].fail;
while(t!=-1 && tree[t].next[j]==-1) t = tree[t].fail;
if(t == -1) tree[son].fail = Root;
else tree[son].fail = tree[t].next[j];
}
que.push(son);
}
}
}
}
bool mark[N];
int query(char s[]) {
int p = Root, ans = 0;
memset(mark, 0, sizeof(mark));
for(int i=0; s[i]; i++) {
mark[p] = 1;
int t = s[i] - 'a';
while(tree[p].next[t]==-1 && p) p = tree[p].fail;
p = tree[p].next[t];
if(p == -1) { p = Root; continue; };
int j = p;
if(!mark[j])
while(j) {
ans += tree[j].cnt;
tree[j].cnt = 0;
j = tree[j].fail;
}
}
return ans;
}
char str[100], s[maxn];
int main() {
int T; scanf("%d", &T);
while(T--) {
tot = 0;
init(Root, -1);
int n; scanf("%d", &n);
while(n--) {
scanf("%s", str);
Insert(str);
}
get_fail();
scanf("%s", s);
int ans = query(s);
printf("%d\n", ans);
}
return 0;
}