• 【距离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.
  • 相关阅读:
    IT痴汉的工作现状24-Just for fun
    &quot;duplicate symbol for architecture i386&quot; 解决的方法
    如何将visual studio 2010编辑模式改为插入???
    教学平台服务器安装环境说明
    Microsoft SQL Server 2008 基本安装说明
    WEB安全测试的类型
    IBM Rational Appscan使用之扫描结果分析
    IBM Rational AppScan使用详细说明
    Security Testing Basics
    ZAP介绍
  • 原文地址:https://www.cnblogs.com/EC-Ecstasy/p/4183471.html
Copyright © 2020-2023  润新知