【距离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.

 

posted @ 2014-12-24 22:07  Ecsy  阅读(372)  评论(0编辑  收藏  举报