题意:AC自动机裸题。
AC自动机:就是kmp+trie树,适用于有多个模式串。
而AC自动机构建的trie树与一般的trie树唯一的区别就是多了一个失败指针fail用来指向作为当前这个单词最长的后缀的模式串的最后一个字母的结点。例如有模式串faed,daj,aed,ed,fad。对应的trie树如下图。
其中faed的结尾结点的fail指针,指向aed的结尾结点,aed的指向ed的结尾结点。
那么如何求fail指针,根据trie树的构建性质,可以看出v.fail=v.fa->fail->p[i]。v.fa指向v的父亲结点。v.p[i]指向边权为(i+'a')的边所指向的v的孩子结点。由此,可以通过bfs的顺序来构建fail,因为每次fail可能需要的结点的深度均<v。
现在已经求得了fail,接下来进行原串ori和整颗树的匹配,在匹配到ori[i],trie[j]时,设k=j,循环k=t[k].fail,显然每次循环都满足到t[1]到t[j]上的树边均能匹配,只要累加t[k].num即可,直到k=0,最后j=trie[j].p[ori[i+1]-'a'],整个大循环直到遍历完整个ori为止。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define PI acos(-1)
#define INF 0x3f3f3f3f
#define NUM 510000
#define debug false
#define ll long long
#define lowbit(x) ((-x)&x)
#define ffor(i,d,u) for(int i=d;i<=u;++i)
#define _ffor(i,u,d) for(int i=u;i>=d;--i)
#define mst(array,Num) memset(array,Num,sizeof(array))
const int p = 1e9+7;
struct Trie
{
int p[26];//p[i]中的i为树边代表的字母对应值-'a'
int fail,num;//记录当前这个单词的数目
}t[NUM];
int cnt=1,n;
string par,ori;
template <typename T>
void read(T& x)
{
x=0;
char c;T t=1;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-'){t=-1;c=getchar();}
do((x*=10)+=((int)(c-'0')));while((c=getchar())>='0'&&c<='9');
x*=t;
}
template <typename T>
void write(T x)
{
int len=0;char c[21];
if(x<0)putchar('-');
x=abs(x);
do{++len;c[len]=(char)((x%10)+'0');}while(x/=10);
_ffor(i,len,1)putchar(c[i]);
}
void add()
{
int k,j=0;
ffor(i,0,par.size()-1)
{
k=(int)(par[i]-'a');
if(t[j].p[k]==0)
t[j].p[k]=++cnt;
j=t[j].p[k];
}
++t[j].num;
}
void getfail()
{
queue < int > q;
int x,y;
ffor(i,0,25)if(t[0].p[i]!=0)t[t[0].p[i]].fail=0,q.push(t[0].p[i]);
while(!q.empty())
{
x=q.front();
q.pop();
ffor(i,0,25)
if(t[x].p[i]!=0)t[t[x].p[i]].fail=t[t[x].fail].p[i],q.push(t[x].p[i]);
else t[x].p[i]=t[t[x].fail].p[i];//优化,若仍=0则匹配失败,整个trie树回到树根重新匹配。
}
}
int mark()
{
int j=0,sum=0,k;
ffor(i,0,ori.size()-1)
{
j=t[j].p[(int)(ori[i]-'a')];
k=j;
while(k!=0&&t[k].num!=-1)
{
sum+=t[k].num;
t[k].num=-1;//记为已经匹配过的
k=t[k].fail;
}
}
return sum;
}
void AC()
{
mst(t,0);
read(n);
while(n--)
{
cin>>par;
add();
}
t[0].fail=0;
getfail();
cin>>ori;
write(mark());
putchar('\n');
}
int main()
{
AC();
return 0;
}