[bzoj3238]差异(后缀数组+单调栈)

Posted Sakits

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj3238]差异(后缀数组+单调栈)相关的知识,希望对你有一定的参考价值。

技术分享

      显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去。所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的。

      接下来问题就是如何把LCP减去。我们先用后缀数组把height求出来,当有一段区间l~r,height[i]为height[l]~height[r]中的最小值,那么在l~r当中随便取两个后缀,他们的LCP则都是height[i],这个很好理解吧。那么l~r这个区间里有(l-i+1)*(r-i+1)对后缀,所以我们最后的答案就要减去2*height[i]*(l-i+1)*(r-i+1)【1≤i≤n】。

      然后就是如何求出每一个i的l~r了,暴力枚举+RMQ显然不行,那我们就用一个单调栈,栈里存着i前面height值比height[i]小的height值的编号,记为j,如果height[j]比height[i]大那么就弹出,那么这段区间的左端点则为栈顶的j+1,右端点同理。这样我们就可以求出每个height的l和r了。

奇丑无比的代码如下:

技术分享
var
  s:ansistring;
  i:longint;
  n,m,l,r,ans,top:int64;
  rk,trk,sa,tsa,sum,h,ll,rr,st:array[0..500005]of int64;

procedure suffix;
var
  i,j,p:longint;
begin
  for i:=1 to n do begin trk[i]:=ord(s[i]);inc(sum[trk[i]]);end;
  for i:=2 to 255 do inc(sum[i],sum[i-1]);
  for i:=n downto 1 do begin sa[sum[trk[i]]]:=i;dec(sum[trk[i]]);end;
  rk[sa[1]]:=1;p:=1;
  for i:=2 to n do begin if trk[sa[i]]<>trk[sa[i-1]] then inc(p);rk[sa[i]]:=p;end;
  m:=p;j:=1;
  while m<n do
  begin
    move(rk,trk,sizeof(rk));fillchar(sum,sizeof(sum),0);p:=0;
    for i:=n-j+1 to n do begin inc(p);tsa[p]:=i;end;
    for i:=1 to n do if sa[i]>j then begin inc(p);tsa[p]:=sa[i]-j;end;
    for i:=1 to n do begin rk[i]:=trk[tsa[i]];inc(sum[rk[i]]);end;
    for i:=2 to n do inc(sum[i],sum[i-1]);
    for i:=n downto 1 do begin sa[sum[rk[i]]]:=tsa[i];dec(sum[rk[i]]);end;
    rk[sa[1]]:=1;p:=1;
    for i:=2 to n do
    begin
      if (trk[sa[i]]<>trk[sa[i-1]])or(trk[sa[i]+j]<>trk[sa[i-1]+j])then inc(p);
      rk[sa[i]]:=p;
    end;
    m:=p;j:=j*2;
  end;
  h[1]:=0;p:=0;
  for i:=1 to n do
  begin
    if rk[i]=1 then continue;
    j:=sa[rk[i]-1];
    while s[i+p]=s[j+p] do inc(p);
    h[rk[i]]:=p;
    if p>0 then dec(p);
  end;
end;

begin
  readln(s);
  n:=length(s);
  s:=s+ ;
  suffix;
  ans:=n*(n-1)*(n+1)div 2;
  h[0]:=-maxlongint;
  for i:=1 to n do
  begin
    while h[i]<=h[st[top]] do dec(top);
    if st[top]=0 then ll[i]:=1
    else ll[i]:=st[top]+1;
    inc(top);
    st[top]:=i;
  end;
  h[n+1]:=-maxlongint;top:=0;st[0]:=n+1;
  for i:=n downto 0 do
  begin
    while h[i]<h[st[top]] do dec(top);
    if st[top]=n+1 then rr[i]:=n
    else rr[i]:=st[top]-1;
    inc(top);
    st[top]:=i;
  end;
  for i:=1 to n do
  ans:=ans-2*(i-ll[i]+1)*(rr[i]-i+1)*h[i];
  writeln(ans);
end.
View Code

 

以上是关于[bzoj3238]差异(后缀数组+单调栈)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3238[Ahoi2013]差异 后缀数组+单调栈

bzoj3238差异[AHOI2013](后缀数组+单调栈)

BZOJ3238差异(后缀数组,单调栈)

bzoj 3238 [Ahoi2013]差异 后缀数组 + 单调栈

bzoj3238 [Ahoi2013]差异

BZOJ3238:[AHOI 2013]差异