• [BZOJ2946] [Poi2000]公共串解题报告|后缀数组


    给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
    单词个数<=5,每个单词长度<=2000
      
     
      尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA...
      (其实是不知道应该怎么用SAM做...
      对于后缀数组而言,多个字符串的公共子串与两个处理起来并没有什么区别
      只要在中间加一些没有用的字符,将多个字符串拼成一个字符串
      然后二分答案,对于一个长度L,在一组除了开头其他height都>=L的区间中如果每个字符串的位置都出现过就可以
      
      应该是第二次这么解决一道公共串的题了..
      然后发现了一些新的东西..
      比如之前处理没有的字符串处理了很久,这次我直接在每两个字符串间添加不同的字符
      理由很简单:
      对于原来就在同一个字符串中的两个后缀,它们后面的字符相同,但是由于长度不同,所以没有影响
      即匹配的时候谁先接触到无用字符谁就更小一些,符合我们的愿望
      而对于原来不在一个字符串中的两个后缀,如果他们后面的字符相同,再加上原本的长度也一样
      匹配的时候height数组算出的答案就会比实际的长度要大
      然而我们现在填了不同的字符就可以很好地避免掉这个问题
     
      不知道为什么...我的SA很长...
      不过无所谓只要好理解不用背代码...长一点也只是敲敲键盘的问题...
      这里是用SAM解这道题的方法
     
     
      1 program bzoj2946;
      2 const maxn = 30010;
      3 var b,sa,rank,tmp,a,pos,height:array[-1..maxn]of longint;
      4     vis,l,r:array[-1..10]of longint;
      5     maxlen,n,m,i,j,lx,rx,mid,ans:longint;
      6     s:ansistring;
      7     ss:array[-1..10]of ansistring;
      8 
      9 
     10 function max(a,b:longint):longint;
     11 begin
     12     if a>b then exit(a) else exit(b);
     13 end;
     14 
     15 procedure Suffix_Array;
     16 var i,j,p,sz,v0,v1,v01,v00:longint;
     17 begin
     18     sz:=max(200,length(s));
     19     for i:=0 to sz do b[i]:=0;
     20     for i:=0 to m-1 do inc(b[a[i]]);
     21     for i:=0 to m-1 do rank[i]:=a[i];
     22     for i:=1 to sz do inc(b[i],b[i-1]);
     23     for i:=m-1 downto 0 do
     24     begin
     25         dec(b[rank[i]]);
     26         sa[b[rank[i]]]:=i;
     27     end;
     28     j:=1;
     29     while j<=m do
     30     begin
     31         p:=0;
     32         for i:=m-j to m-1 do
     33         begin
     34             tmp[p]:=i;inc(p);
     35         end;
     36         for i:=0 to m-1 do if sa[i]-j>=0 then
     37         begin
     38             tmp[p]:=sa[i]-j;inc(p);
     39         end;
     40         for i:=0 to sz do b[i]:=0;
     41         for i:=0 to m-1 do inc(b[rank[i]]);
     42         for i:=1 to sz do inc(b[i],b[i-1]);
     43         for i:=m-1 downto 0 do
     44         begin
     45             dec(b[rank[tmp[i]]]);
     46             sa[b[rank[tmp[i]]]]:=tmp[i];
     47         end;
     48         tmp[sa[0]]:=0;p:=0;
     49         for i:=1 to m-1 do
     50         begin
     51             v0:=sa[i-1];v1:=sa[i];
     52             if v0+j<m then v00:=rank[v0+j] else v00:=-1;
     53             if v1+j<m then v01:=rank[v1+j] else v01:=-1;
     54             if (rank[v0]=rank[v1])and(v00=v01) then tmp[sa[i]]:=p else
     55             begin
     56                 inc(p);tmp[sa[i]]:=p;
     57             end;
     58         end;
     59         for i:=0 to m-1 do rank[i]:=tmp[i];
     60         j:=j << 1;
     61     end;
     62 end;
     63     
     64 
     65 function compare(i,j,x:longint):longint;
     66 begin
     67     while (i+x-1<m)and(j+x-1<m)and(a[i+x-1]=a[j+x-1]) do inc(x);
     68     exit(x-1);
     69 end;
     70 
     71 procedure calc_height;
     72 var i:longint;
     73 begin
     74     if rank[0]=0 then height[0]:=0 else height[0]:=compare(0,sa[rank[0]-1],1);
     75     for i:=1 to m-1 do
     76     if rank[i]=0 then height[i]:=0 else height[i]:=compare(i,sa[rank[i]-1],max(height[i-1],1));
     77 end;
     78 
     79 function solve(x:longint):boolean;
     80 var i,j,k:longint;
     81 begin
     82     for i:=0 to n do vis[i]:=-1;
     83     i:=0;
     84     while i<m do
     85     begin
     86         j:=i+1;
     87         while (j<m)and(height[sa[j]]>=x) do inc(j);
     88         for k:=i to j-1 do vis[pos[sa[k]]]:=i;
     89         for k:=1 to n do if vis[k]<>i then break;
     90         if vis[k]=i then exit(true);
     91         i:=j;
     92     end;
     93     exit(false);
     94 end;
     95 
     96 begin
     97     readln(n);s:='';maxlen:=0;
     98     for i:=1 to n do
     99     begin
    100         readln(ss[i]);
    101         if length(ss[i])>maxlen then maxlen:=length(ss[i]);
    102     end;
    103     maxlen:=1 << (trunc(ln(maxlen)/ln(2))+1);
    104     fillchar(pos,sizeof(pos),0);
    105     for i:=1 to n do
    106     begin
    107         l[i]:=length(s)+1;
    108         s:=s+ss[i];
    109         r[i]:=length(s);
    110         for j:=l[i] to r[i] do pos[j-1]:=i;
    111         for j:=1 to maxlen do s:=s+chr(i);
    112     end;
    113     m:=length(s);
    114     for i:=0 to m-1 do a[i]:=ord(s[i+1]);
    115     Suffix_Array;
    116     Calc_Height;
    117     Lx:=1;Rx:=maxlen;ans:=0;
    118     while Lx<=Rx do
    119     begin
    120         mid:=(Lx+Rx) >> 1;
    121         if solve(mid) then
    122         begin
    123             ans:=mid;Lx:=mid+1;
    124         end else Rx:=mid-1;
    125     end;
    126     writeln(ans);
    127 end.
  • 相关阅读:
    SQL 运算符
    Shiro 入门
    SSM 整合配置
    MyBatis 入门
    Git 常用命令
    JSP
    Servlet
    Oracle 基础
    JDBC
    Java Thread
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4478294.html
Copyright © 2020-2023  润新知