• [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
  • 相关阅读:
    转换流--OutputStreamWriter类与InputStreamReader类
    Android getResources的作用和须要注意点
    sqlit使用要点之引入libsqlite3.dylib
    C语言文件操作之fgets()
    5款伊思儷超媒體繁体游戏 中文简体补丁
    memcpy的使用方法总结
    开发人员改变世界的初心
    expect
    HDU 1061 N^N (n的n次方的最后一位)
    linux杂谈(二十):apache服务配置
  • 原文地址:https://www.cnblogs.com/Sakits/p/5351175.html
Copyright © 2020-2023  润新知