zoukankan      html  css  js  c++  java
  • [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]中的最小值,那么随便取rk[l]~rk[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
  • 相关阅读:
    Proj THUDBFuzz Paper Reading: PMFuzz: Test Case Generation for Persistent Memory Programs
    入围 WF 后训练记
    算法竞赛历程
    2021 多校 杭电 第十场
    2021 多校 杭电 第九场
    2021 多校 牛客 第十场
    2021 多校 牛客 第九场
    2021 多校 杭电 第八场
    2021 多校 杭电 第六场
    2021 多校 杭电 第七场
  • 原文地址:https://www.cnblogs.com/Sakits/p/5351175.html
Copyright © 2011-2022 走看看