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
  • 相关阅读:
    CSS3 Animation
    css形状大全
    HTML5 表单属性
    HTML5 Input 类型
    HTML 5 服务器发送事件
    jq制作博客已存在多少天
    Java网络编程与NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector
    Java网络编程和NIO详解3:IO模型与Java网络编程模型
    Java网络编程与NIO详解2:JAVA NIO 一步步构建IO多路复用的请求模型
    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
  • 原文地址:https://www.cnblogs.com/Sakits/p/5351175.html
Copyright © 2011-2022 走看看