ac自动机,令人神往的名字。。。
ac自动机:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
poj2778:http://hi.baidu.com/%D2%D5%C1%D6010/blog/item/6db06ccf0a3b440993457e7b.html
ac自动机,多模式匹配,学了kmp,tire后,将其融合的算法。
首先建立字典树(tire),运用kmp的思想,构造fail指针。构造方法:将根加入队列,逐层广搜,根的fail指针指向自己,每搜到一个节点,设值为‘A',访问其祖先的fail指针,
判断其值为'A'的节点是否为空,若不是,则fail指针指向值为‘A’的节点,若是,则继续访问其fail指针,若到根也为找到适合节点,则指向根。匹配时只需设两个指针扫描串和树,
若匹配,则同时后移,若不匹配,则串指针不动,树指针移向fail指针。
poj 2778 给定m个串,要求生成长度为n,不包含该m个串的序列的方案数。
用m个串构造tire树(若某串包含另一串则不加入),与fail指针,将每个节点编号,表示后缀为其到根的状态。构造矩阵,考虑某个节点,当后面添上某字符时,如果有该子节点,
则判断是否是叶子节点(即加入后会成为m串之一),不是,则该节点到其子节点权值加一,是,则不考虑;若无该子节点,则找其fail指针,直到有该子节点,或到根停下,
若有该子节点,则依上一情况讨论,若到根也无该子节点,则该节点到根权值加一。
构造完矩阵,运用矩阵乘法即可。
这道题实际上是用ac自动机转化为图上的路径条数问题,可以在矩阵乘法十道经典题中找到。
const q:array[1..4]of char=('A','C','T','G'); mo=100000; type arry=array[0..100,0..100]of int64; var next:array[0..10000,'A'..'T']of longint; pow,st,p:array[0..10000]of longint; a,b,mul:arry; n,m,ss:longint; ans:int64; procedure link(n:string); var x,i,l:longint; begin x:=0;i:=1;l:=length(n); while i<=l do begin if next[x,n[i]]=0 then begin inc(ss);next[x,n[i]]:=ss end; x:=next[x,n[i]]; if pow[x]=1 then exit; inc(i) end; pow[x]:=1 end; procedure bfs(s:longint); var h,r,i,ne,na,nr:longint; flag:boolean; begin h:=0;r:=1;st[1]:=s; repeat inc(h);ne:=st[h]; if ne=6 then ne:=ne; for i:=1 to 4 do if pow[ne]=0 then begin if next[ne,q[i]]<>0 then begin nr:=ne; while p[nr]<>nr do begin nr:=p[nr]; if next[nr,q[i]]<>0 then begin nr:=next[nr,q[i]];break end; end; p[next[ne,q[i]]]:=nr;pow[next[ne,q[i]]]:=pow[next[ne,q[i]]] or pow[nr]; inc(r);st[r]:=next[ne,q[i]]; na:=next[ne,q[i]];flag:=true; while na<>p[na] do begin if pow[na]=1 then begin flag:=false;break end; na:=p[na] end; if flag then inc(b[ne,next[ne,q[i]]]); end else begin na:=ne;flag:=true; while p[na]<>na do begin na:=p[na];nr:=next[na,q[i]]; if nr<>0 then break end; nr:=next[na,q[i]]; if pow[nr]=0 then inc(b[ne,nr]); end end until h>=r end; procedure mul1; var i,j,k,e:longint; begin fillchar(mul,sizeof(mul),0); for i:=0 to ss do for j:=0 to ss do for k:=0 to ss do begin mul[i,j]:=mul[i,j]+(a[i,k]*b[k,j]); IF mul[i,j]>mo then mul[i,j]:=mul[i,j] mod mo end; for i:=0 to ss do for j:=0 to ss do a[i,j]:=mul[i,j]; end; procedure mul2; var i,j,k,e:longint; begin fillchar(mul,sizeof(mul),0); for i:=0 to ss do for j:=0 to ss do for k:=0 to ss do begin mul[i,j]:=(mul[i,j]+(b[i,k]*b[k,j])); IF mul[i,j]>mo then mul[i,j]:=mul[i,j] mod mo end; for i:=0 to ss do for j:=0 to ss do b[i,j]:=mul[i,j]; end; procedure fgm(e:longint); var i:longint; begin for i:=0 to ss do a[i,i]:=1; while e<>0 do begin if e and 1=1 then mul1; mul2; e:=e>>1 end end; procedure init; var i,j:longint; x:string; begin fillchar(b,sizeof(b),0);fillchar(a,sizeof(a),0); fillchar(next,sizeof(next),0);fillchar(pow,sizeof(pow),0); fillchar(p,sizeof(p),0);fillchar(st,sizeof(st),0); readln(m,n); for i:=1 to m do begin readln(x);link(x) end; bfs(0); fgm(n); ans:=0; for i:=0 to ss do ans:=(ans+a[0,i]) mod mo; writeln(ans mod mo) end; begin assign(input,'2778.in');reset(input); assign(output,'2778.out');rewrite(output); while not seekeof do init; close(input);close(output) end.