【距离GDOI:128天】【POJ2778】DNA Sequence(AC自动机+矩阵加速)
已经128天了?怎么觉得上次倒计时150天的日子还很近啊
....好吧为了把AC自动机搞透我也是蛮拼的..把1030和这道题对比了无数遍...最终结论是...无视时间复杂度,1030可以用这种写法解..但是!!对于26个字母的就算了吧...
其实这道题体现的是一个对于AC自动机等价态,即fail的表示和处理上:
通常有两种方法处理等价态,第一是互为等价态的点各自记录各自的信息。匹配的时候需要遍历所有等价态以判断是否匹配成功。next指针可能为空,需要匹配时进行判断是否需要走fail指针。
第二是所有等价态中的点记录本身以及所有比它浅的点的信息总和(匹配成功的单词总数),匹配时不需要走等价态以判断匹配成功与否。next指针不为空,直接指向本应通过fail指针寻找到的那个状态。我的新的模版就是用的这种方式...因为这样感觉好写而且也快...
然后这道题,我们把AC自动机看成一个有向图,这样用mat[i,j]表示由节点i到节点j上有一条路...这个矩阵的n次幂表示从i恰好走n步到达j的路径有几条...大概是这样
然后我又TLE了..
const maxn=105; maxs=3; vv=100000; type mattype=record n,m:longint; a:array[0..110,0..110] of longint; end; rectype=array[0..15] of longint; var next:array[0..maxn,0..maxs] of longint; pd:array[0..maxn] of boolean; q,f:array[0..maxn] of longint; ori:mattype; n,m,tot,head,tail,root:longint; procedure push(x:longint); begin inc(tail); q[tail]:=x; end; operator *(x,y:mattype)tmp:mattype; var i,j,k:longint; begin tmp.n:=x.n; tmp.m:=y.m; fillchar(tmp.a,sizeof(tmp.a),0); for i:= 1 to tmp.n do for j:= 1 to tmp .m do for k:= 0 to x.m do tmp.a[i,j]:=(tmp.a[i,j]+int64(x.a[i,k])*y.a[k,j] mod vv) mod vv; exit(tmp); end; function pow(x:mattype;k:longint):mattype; var tmp:mattype; i:longint; begin tmp.n:=x.n; tmp.m:=x.n; fillchar(tmp.a,sizeof(tmp.a),0); for i:= 1 to x.n do tmp.a[i,i]:=1; while k>0 do begin if (k and 1)=1 then tmp:=tmp*x; x:=x*x; k:=k>>1; end; exit(tmp); end; function new:longint; var i:longint; begin pd[tot]:=false; for i:= 0 to maxs do next[tot,i]:=-1; inc(tot); exit(tot-1); end; procedure insert(s:rectype); var i,c,v:longint; begin v:=root; for i:= 1 to s[0] do begin c:=s[i]; if next[v,c]=-1 then next[v,c]:=new; v:=next[v,c]; end; pd[v]:=true; end; procedure build; var i,v:longint; begin f[root]:=root; head:=1; tail:=0; for i:= 0 to maxs do if next[root,i]=-1 then next[root,i]:=root else begin f[next[root,i]]:=root; push(next[root,i]); end; while head<=tail do begin v:=q[head]; inc(head); if pd[f[v]] then pd[v]:=true; for i:= 0 to maxs do if next[v,i]=-1 then next[v,i]:=next[f[v],i] else begin f[next[v,i]]:=next[f[v],i]; push(next[v,i]); end; end; end; function change(c:char):longint; begin case c of 'A': exit(0); 'C': exit(1); 'G': exit(2); 'T': exit(3); end; end; procedure init; var ss:string; s:rectype; i,j:longint; begin tot:=1; root:=new; readln(n,m); for i:= 1 to n do begin readln(ss); s[0]:=length(ss); for j:= 1 to s[0] do s[j]:=change(ss[j]); insert(s); end; dec(tot); build; ori.n:=tot; ori.m:=tot; for i:= root to tot do for j:= 0 to maxs do if not pd[next[i,j]] then inc(ori.a[i,next[i,j]]); end; procedure solve; var ans,i:longint; begin ori:=pow(ori,m); ans:=0; for i:= 1 to ori.n do ans:=(ans+ori.a[1,i]) mod vv; writeln(ans); end; Begin init; solve; End.