算法模板:AC自动机模板

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.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值