明细 ac 自动机模板题,我们先把 n 个单词建立 ac 自动机树,然后统计每个单词在每个单词在相应的结尾上出现的次数(在单词结尾的位置打上标记)。
然后用 s 在自动机树上进行匹配,对于每配到一个位置节点,我们都沿着这个节点,while 循环跳这个点的 fail 指针,如果每跳到一个点就就加上一个这个点结尾的单词的个数。
代码
#include<bits/stdc++.h>
using namespace std;constint N =5e5+10, M =1e6+10;int tr[N][26], fa[N], idx, num[N];char s[M];voidinit(){memset(tr,0,sizeof tr);memset(fa,0,sizeof fa);memset(num,0,sizeof num);
idx =0;}voidinsert(char s[]){int p =0;for(int i =0; s[i]; i ++){int c = s[i]-'a';if(tr[p][c]==0) tr[p][c]=++ idx;
p = tr[p][c];}
num[p]++;}voidbuild(){int p =0;
queue<int> q;for(int i =0; i <26; i ++){if(tr[p][i]) q.push(tr[p][i]);}while(q.size()){
p = q.front(); q.pop();for(int i =0; i <26; i ++){if(tr[p][i]) fa[tr[p][i]]= tr[fa[p]][i], q.push(tr[p][i]);else tr[p][i]= tr[fa[p]][i];}}}intmain(){int T;scanf("%d",&T);while(T --){init();int n;scanf("%d",&n);for(int i =0; i < n; i ++){scanf("%s", s);insert(s);}build();scanf("%s", s);int p =0, ans =0;for(int i =0; s[i]; i ++){int c = s[i]-'a';
p = tr[p][c];int t = p;while(t){
ans += num[t];
num[t]=0;
t = fa[t];}}printf("%d\n", ans);}return0;}