pascalAC自动机模板
//AC自动机模板
var
i,j,k,n,m,ans,total,l,r:longint;
s,v:ansistring;
t:array[0..200000,1..26]of longint;
a,c,tail:array[0..200000]of longint;
dl:array[1..200000]of longint;
procedure dg(x,y:longint);
begin
if y<=length(v) then //如果还没走到子串底
begin
if t[x,ord(v[y])-96]=0 then //如果还没有当前字符编号的子节点
begin
inc(total); //更新节点数
t[x,ord(v[y])-96]:=total; //更新子节点编号
a[total]:=ord(v[y])-96; //节点储存当前字符
end;
dg(t[x,ord(v[y])-96],y+1); //前往当前字符编号的子节点
end
else inc(c[x]); //记录词数
end;
begin
assign(input,'sf_acautomaton.in');reset(input);
assign(output,'sf_acautomaton.out');rewrite(output);
readln(n);
readln(m);
for i:=1 to m do
begin
readln(v);
dg(0,1);
end;
r:=0;
for i:=1 to 26 do
begin
if t[0,i]<>0 then
begin
inc(r);
dl[r]:=t[0,i]; //初始化宽搜队列,根节点的子节点的失败指针必须指向根节点
end;
end;
l:=1;
while l<=r do
begin
j:=dl[l];
for i:=1 to 26 do
begin
if t[j,i]<>0 then //当前节点有这个字符编号的子节点
begin
k:=tail[j]; //当前字符的失败指针
while (t[k,i]=0)and(k<>0) do k:=tail[k];//如果失败指针指向的点没有与当前字符编号(i)相同的子节点,
//则沿着失败指针继续走,直到走到根节点为止
if t[k,i]<>0 then tail[t[j,i]]:=t[k,i];//如果停止走失败指针,说明要不走到了根节点,
//要不有与当前字符编号(i)相同的子节点
inc(r);
dl[r]:=t[j,i];//将当前子节点加入队列,好更新其子节点
end;
end;
inc(l);
end;
j:=0;
readln(s);
ans:=0;
for i:=1 to n do
begin
while (t[j,ord(s[i])-96]=0)and(j<>0) do j:=tail[j]; //如果无法匹配当前字符,则沿着失败指针走,直到走到根节点
if t[j,ord(s[i])-96]<>0 then
begin
j:=t[j,ord(s[i])-96]; //沿着编号走向子节点
ans:=ans+c[j]; //更新答案
k:=tail[j]; //沿着失败指针走,继续更新答案
while k<>0 do
begin
ans:=ans+c[k];
k:=tail[k]; //直到走到根节点
end;
end;
end;
writeln(ans);
close(input);
close(output);
end.