zoukankan      html  css  js  c++  java
  • [BZOJ2946][Poi2000]公共串解题报告|后缀自动机

      鉴于SAM要简洁一些...于是又写了一遍这题...

      不过很好呢又学到了一些新的东西...

      这里是用SA做这道题的方法

      首先还是和两个字符串的一样,为第一个字符串建SAM

      然后每一个字符串再在这个SAM上跑匹配

      然而我们最后要的答案是什么呢?

      是某个在所有字符串中匹配长度最小值最大的状态子串

      然后对于每一个字符串

      我们可以记录它在每一个状态子串上的最大匹配长度

      最后需要一个非常关键的转移

      就是用当前节点的值更新fail指针指向的节点

      比如这种情况

      如果一次匹配到左边的三个节点,一次匹配到右边的两个节点(两次匹配在不同的字符串中)

      那么显然,这两个字符串的公共子串长度为2是存在的

      但是由于我们没有转移过,fail指针指向的点没有储存前面的信息就会出错

      

      然后至于转移的顺序,我们可以按照深度顺序

      这个可以用桶排实现

     1 program bzoj2946;
     2 const maxn = 100010;
     3 var n,i,j,now,maxl,root,c,tot,cnt,t:longint;
     4     s:array[1..5]of ansistring;
     5     mx,fail,q,b,ans,tem:array[-1..maxn]of longint;
     6     a:array[-1..maxn,-1..30]of longint;
     7 
     8 function max(a,b:longint):longint;
     9 begin
    10     if a>b then exit(a) else exit(b);
    11 end;
    12 
    13 function min(a,b:longint):longint;
    14 begin
    15     if a<b then exit(a) else exit(b);
    16 end;
    17 
    18 function insert(p,c:longint):longint;
    19 var np,q,nq:longint;
    20 begin
    21     inc(cnt);np:=cnt;mx[np]:=mx[p]+1;
    22     while (p<>0)and(a[p,c]=0) do
    23     begin
    24         a[p,c]:=np;p:=fail[p];
    25     end;
    26     if p=0 then fail[np]:=root else
    27     begin
    28         q:=a[p,c];
    29         if mx[q]=mx[p]+1 then fail[np]:=q else
    30         begin
    31             inc(cnt);nq:=cnt;mx[nq]:=mx[p]+1;
    32             a[nq]:=a[q];
    33             fail[nq]:=fail[q];
    34             fail[np]:=nq;fail[q]:=nq;
    35             while a[p,c]=q do
    36             begin
    37                 a[p,c]:=nq;p:=fail[p];
    38             end;
    39         end;
    40     end;
    41     exit(np);
    42 end;
    43 
    44 begin
    45     readln(n);
    46     for i:=1 to n do readln(s[i]);
    47     cnt:=1;root:=1;t:=root;
    48     for i:=1 to length(s[1]) do t:=insert(t,ord(s[1,i])-97);
    49     for i:=2 to cnt do ans[i]:=mx[i];
    50     fillchar(b,sizeof(b),0);
    51     for i:=2 to cnt do inc(b[mx[i]]);
    52     for i:=2 to cnt do inc(b[i],b[i-1]);
    53     for i:=2 to cnt do ans[i]:=mx[i];
    54     for i:=cnt downto 2 do
    55     begin
    56         dec(b[mx[i]]);
    57         q[b[mx[i]]]:=i;
    58     end;
    59     for i:=1 to n do
    60     begin
    61         now:=root;maxl:=0;
    62         fillchar(tem,sizeof(tem),0);
    63         for j:=1 to length(s[i]) do
    64         begin
    65             c:=ord(s[i][j])-97;
    66             if a[now,c]<>0 then begin now:=a[now,c];inc(maxl);end else
    67             begin
    68                 while (now<>0)and(a[now,c]=0) do now:=fail[now];
    69                 if now=0 then begin now:=root;maxl:=0;end else begin maxl:=mx[now]+1;now:=a[now,c];end;
    70             end;
    71             tem[now]:=max(tem[now],maxl);
    72         end;
    73         for j:=cnt downto 0 do tem[fail[q[j]]]:=max(tem[fail[q[j]]],tem[q[j]]);
    74         for j:=2 to cnt do ans[j]:=min(ans[j],tem[j]);
    75     end;
    76     tot:=0;
    77     for i:=2 to cnt do if ans[i]>tot then tot:=ans[i];
    78     writeln(tot);
    79 end.

      比较了一下..代码减少了三分之一,空间缩小了十分之九...最主要写起来简单多了

      SAM大法好

      

      05/.May

  • 相关阅读:
    Android应用性能测试之CPU和内存占用
    每天一个linux命令(30): chown命令
    安装apk时出现错误Failure [INSTALL_FAILED_DEXOPT]问题解决的方法
    android adb shell 命令大全
    adb logcat命令查看并过滤android输出log
    Ubuntu里字符编码设置
    linux下GBK->UTF-8文件编码批量转换脚本
    Android开发之如何保证Service不被杀掉(broadcast+system/app)
    android的m、mm、mmm编译命令的使用
    解决 samba不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4478678.html
Copyright © 2011-2022 走看看