zoukankan      html  css  js  c++  java
  • bzoj3796

    好像已经很久没有做后缀数组的题目,导致这种题一开始没想出来
    看到公共子串肯定想到后缀数组吧,但我都忘了最长公共子串怎么求了
    重要的性质:最长公共子串=max(h[i])名次相邻的两个后缀要分别属于s1,s2串 具体怎么证很简单
    这道题多了一个条件,就是公用子串不能包含某个串——很明显想到KMP
    我们可以预处理与s3匹配的起始位置,然后处理每个点右边最近的起始位置
    然后在穷举h[i]的时候判断一下即可

      1 var h,f,x,y,sum,sa,rank:array[0..120000] of longint;
      2     v:array[0..120000] of boolean;
      3     j,t,st,en,ans,i,p,l,n,m:longint;
      4     s,ss:ansistring;
      5     fl:boolean;
      6 
      7 function max(a,b:longint):longint;
      8   begin
      9     if a>b then exit(a) else exit(b);
     10   end;
     11 
     12 procedure suffix;
     13   var i,p,j,m:longint;
     14   begin
     15     m:=150;
     16     for i:=1 to n do
     17     begin
     18       y[i]:=ord(s[i]);
     19       inc(sum[y[i]]);
     20     end;
     21     for i:=1 to m do
     22       inc(sum[i],sum[i-1]);
     23     for i:=n downto 1 do
     24     begin
     25       sa[sum[y[i]]]:=i;
     26       dec(sum[y[i]]);
     27     end;
     28     p:=1;
     29     rank[sa[1]]:=1;
     30     for i:=2 to n do
     31     begin
     32       if y[sa[i]]<>y[sa[i-1]] then inc(p);
     33       rank[sa[i]]:=p;
     34     end;
     35     m:=p;
     36     j:=1;
     37     while m<n do
     38     begin
     39       y:=rank;
     40       fillchar(sum,sizeof(sum),0);
     41       p:=0;
     42       for i:=n-j+1 to n do
     43       begin
     44         inc(p);
     45         x[p]:=i;
     46       end;
     47       for i:=1 to n do
     48         if sa[i]>j then
     49         begin
     50           inc(p);
     51           x[p]:=sa[i]-j;
     52         end;
     53       for i:=1 to n do
     54       begin
     55         rank[i]:=y[x[i]];
     56         inc(sum[rank[i]]);
     57       end;
     58       for i:=1 to m do
     59         inc(sum[i],sum[i-1]);
     60       for i:=n downto 1 do
     61       begin
     62         sa[sum[rank[i]]]:=x[i];
     63         dec(sum[rank[i]]);
     64       end;
     65       p:=1;
     66       rank[sa[1]]:=1;
     67       for i:=2 to n do
     68       begin
     69         if (y[sa[i]]<>y[sa[i-1]]) or (y[sa[i-1]+j]<>y[sa[i]+j]) then inc(p);
     70         rank[sa[i]]:=p;
     71       end;
     72       m:=p;
     73       j:=j shl 1;
     74     end;
     75     p:=0;
     76     h[1]:=0;
     77     for i:=1 to n do
     78     begin
     79       if rank[i]=1 then continue;
     80       j:=sa[rank[i]-1];
     81       while s[i+p]=s[j+p] do inc(p);
     82       h[rank[i]]:=p;
     83       if p>0 then dec(p);
     84     end;
     85   end;
     86 
     87 begin
     88   readln(s);
     89   readln(ss);
     90   p:=length(s)+1;
     91   s:=s+chr(1)+ss+chr(2);
     92   n:=length(s);
     93 
     94   readln(ss);
     95   l:=length(ss);
     96   ss:=ss+' ';
     97   for i:=2 to l do
     98   begin
     99     j:=f[i-1];
    100     while (j>0) and (ss[j+1]<>ss[i]) do j:=f[j];
    101     if ss[j+1]=ss[i] then f[i]:=j+1 else f[i]:=0;
    102   end;
    103 
    104   j:=0;
    105   for i:=1 to p-1 do
    106   begin
    107     while (j>0) and (ss[j+1]<>s[i]) do j:=f[j];
    108     if ss[j+1]=s[i] then
    109     begin
    110       inc(j);
    111       if j=l then v[i-l+1]:=true;
    112     end
    113     else j:=0;
    114   end;
    115 
    116   t:=100000007;
    117   for i:=p-1 downto 1 do
    118   begin
    119     if v[i] then t:=i;
    120     f[i]:=t;  //右边最近的匹配起始节点
    121   end;
    122   suffix;
    123   ans:=0;
    124   for i:=2 to n do
    125   begin
    126     fl:=false;
    127     if (sa[i]<p) and (sa[i-1]>p) and (sa[i-1]<n) then
    128     begin
    129       st:=sa[i];
    130       en:=f[st];
    131       fl:=true;
    132     end;
    133     if (sa[i]>p) and (sa[i]<n) and (sa[i-1]<p) then
    134     begin
    135       st:=sa[i-1];
    136       en:=f[st];
    137       fl:=true;
    138     end;
    139     if fl then
    140     begin
    141       if h[i]>=en-st+l then  //判断是否包含了匹配串
    142         ans:=max(ans,en-st+l-1)
    143       else ans:=max(ans,h[i]);
    144     end;
    145   end;
    146   writeln(ans);
    147 end.
    View Code
  • 相关阅读:
    老人与小孩
    搭讪
    VIM 如何使用系统的剪切板
    Linux 下如何安装 .rpm 文件
    Linux 下如何安装 .bin 文件
    Tomorrow Is A New Day
    Hive 学习(五) Hive之HSQL基础
    Hive 学习(二) hive安装
    Hive 学习(四) Hive的数据类型
    Hive 学习(三) Hive的DDL操作
  • 原文地址:https://www.cnblogs.com/phile/p/4472949.html
Copyright © 2011-2022 走看看