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

 

转载于:https://www.cnblogs.com/phile/p/4472949.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值