HDU2222 Keywords Search AC自动机
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - HDU2222
题意概括
先给出一些模式串,然后给出一个母串,统计先前给出的模式串中,有多少个在母串中出现。多组数据。
题解
AC自动机模板题。
首先根据输入数据构建AC自动机。
然后对于每一位,沿着fail指针走,全部统计并累加。
有一个小小的优化,就是走过的都标记为-1,下次碰到-1就不走了。因为如果这个节点的标记为-1,那么它的fail一再在它之前就标记成-1了(即统计过了)。
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=10005,L1=55,L2=1000005; int T,n,cnt; char ch[L1],str[L2]; struct Trie{ int e,fail,Next[26]; void init(){ e=fail=0; memset(Next,0,sizeof Next); } }tree[N*L1]; void AC_init(){ cnt=1; tree[0].init(); tree[1].init(); for (int i=0;i<26;i++) tree[0].Next[i]=1; } void build(char ch[]){ int rt=1,t,len=strlen(ch); for (int i=0;i<len;i++){ t=ch[i]-'a'; if (!tree[rt].Next[t]){ tree[++cnt].init(); tree[rt].Next[t]=cnt; } rt=tree[rt].Next[t]; } tree[rt].e++; } int q[N*L1],head,tail; void build_AC(){ int rt,k,son; head=tail=0; tree[0].fail=1,tree[1].fail=0; q[++tail]=1; while (head<tail){ rt=q[++head]; for (int i=0;i<26;i++){ son=tree[rt].Next[i]; if (!son){ tree[rt].Next[i]=tree[tree[rt].fail].Next[i]; continue; } k=tree[rt].fail; while (!tree[k].Next[i]) k=tree[k].fail; tree[son].fail=tree[k].Next[i]; q[++tail]=son; } } } int solve(){ int rt=1,t,len=strlen(str); int ans=0; for (int i=0;i<len;i++){ t=str[i]-'a'; rt=tree[rt].Next[t]; int k=rt; while (~tree[k].e){ ans+=tree[k].e; tree[k].e=-1; k=tree[k].fail; } } return ans; } int main(){ scanf("%d",&T); while (T--){ scanf("%d",&n); AC_init(); for (int i=0;i<n;i++){ scanf("%s",ch); build(ch); } build_AC(); scanf("%s",str); printf("%d\n",solve()); } return 0; }