zoukankan      html  css  js  c++  java
  • 【BZOJ3238】差异(后缀数组,单调栈)

    题意:

    思路:显然len(t[i])+len(t[j])这部分的和是一定的

    那么问题就在于如何快速求出两两之间lcp之和

    考虑将它们排名后用SA可以很方便的求出lcp,且对答案没有影响,因为形式都是数对

    所以用SA求出height

    每个位置的height作为lcp的区间为扩展到最左最右,直到height[x]<height[i],height[y]<height[i]

    这样合法的左区间为[x+1,i],右区间为[i,y-1]

    考虑如何维护一个支持寻找最靠近当前位置的比当前位置上的数小的位置

    这个可以用两次单调栈维护

    但还要考虑到重复计算的情况,比如有多个最小值覆盖了全部区域

    我们可以在比较时其中一次取等号,一次不取

      1 var x,y,sa,rank,height,wc,wd,a:array[0..600000]of longint;
      2     l,r:array[1..600000]of int64;
      3     stk:array[1..600000]of longint;
      4     n,i,m,top:longint;
      5     ans,j:int64;
      6     ch:ansistring;
      7 
      8 function min(x,y:longint):longint;
      9 begin
     10  if x<y then exit(x);
     11  exit(y);
     12 end;
     13 
     14 function cmp(a,b,l:longint):boolean;
     15 begin
     16  exit((y[a]=y[b])and(y[a+l]=y[b+l]));
     17 end;
     18 
     19 procedure swap(var x,y:longint);
     20 var t:longint;
     21 begin
     22  t:=x; x:=y; y:=t;
     23 end;
     24 
     25 procedure getsa(n:longint);
     26 var i,j,p:longint;
     27 begin
     28  for i:=0 to n-1 do
     29  begin
     30   x[i]:=a[i];
     31   inc(wc[x[i]]);
     32  end;
     33  for i:=1 to m-1 do wc[i]:=wc[i-1]+wc[i];
     34  for i:=n-1 downto 0 do
     35  begin
     36   dec(wc[x[i]]);
     37   sa[wc[x[i]]]:=i;
     38  end;
     39  j:=1; p:=1;
     40  while p<n do
     41  begin
     42   p:=0;
     43   for i:=n-j to n-1 do
     44   begin
     45    y[p]:=i; inc(p);
     46   end;
     47   for i:=0 to n-1 do
     48    if sa[i]>=j then begin y[p]:=sa[i]-j; inc(p); end;
     49   for i:=0 to n-1 do wd[i]:=x[y[i]];
     50   for i:=0 to m-1 do wc[i]:=0;
     51   for i:=0 to n-1 do inc(wc[wd[i]]);
     52   for i:=1 to m-1 do wc[i]:=wc[i-1]+wc[i];
     53   for i:=n-1 downto 0 do
     54   begin
     55    dec(wc[wd[i]]);
     56    sa[wc[wd[i]]]:=y[i];
     57   end;
     58   for i:=0 to n do swap(x[i],y[i]);
     59   p:=1; x[sa[0]]:=0;
     60   for i:=1 to n-1 do
     61    if cmp(sa[i-1],sa[i],j) then x[sa[i]]:=p-1
     62     else begin x[sa[i]]:=p; inc(p); end;
     63   j:=j<<1;
     64   m:=p;
     65  end;
     66 end;
     67 
     68 procedure getheight(n:longint);
     69 var i,j,k:longint;
     70 begin
     71  k:=0;
     72  for i:=1 to n do rank[sa[i]]:=i;
     73  for i:=0 to n-1 do
     74  begin
     75   if k>0 then dec(k);
     76   j:=sa[rank[i]-1];
     77   while a[i+k]=a[j+k] do inc(k);
     78   height[rank[i]]:=k;
     79  end;
     80 end;
     81 
     82 begin
     83  assign(input,'bzoj3238.in'); reset(input);
     84  assign(output,'bzoj3238.out'); rewrite(output);
     85  readln(ch);
     86  n:=length(ch);
     87  for i:=0 to n-1 do a[i]:=ord(ch[i+1])-ord('a')+1;
     88  a[n]:=0; m:=300;
     89  getsa(n+1);
     90  getheight(n);
     91  stk[1]:=1; height[1]:=-maxlongint; top:=1;
     92  for i:=2 to n do
     93  begin
     94   while (top>0)and(height[i]<height[stk[top]]) do dec(top);
     95   if stk[top]=1 then l[i]:=2
     96    else l[i]:=stk[top]+1;
     97   inc(top); stk[top]:=i;
     98  end;
     99 
    100  stk[1]:=n+1; height[n+1]:=-maxlongint; top:=1;
    101  for i:=n downto 2 do
    102  begin
    103   while (top>0)and(height[i]<=height[stk[top]]) do dec(top);
    104   if stk[top]=n+1 then r[i]:=n
    105    else r[i]:=stk[top]-1;
    106   inc(top); stk[top]:=i;
    107  end;
    108 
    109 
    110  ans:=int64(n-1)*int64(n)*(n+1) div 2;
    111  for i:=2 to n do ans:=ans-2*(-l[i]+i+1)*(r[i]-i+1)*height[i];
    112  //for i:=2 to n+1 do writeln(l[i],' ',r[i]);
    113  writeln(ans);
    114  close(input);
    115  close(output);
    116 end.
  • 相关阅读:
    解决Redis之MISCONF Redis is configured to save RDB snapshots
    lnmp一键安装redis以及php组件
    多版本PHP使用composer
    composer设置成阿里云镜像
    Yaf 简介
    Ubuntu配置php7.2开机启动
    Ubuntu查看开机日志
    ssh生成公钥
    Ubuntu系统如何分区
    初始化一个yaf项目
  • 原文地址:https://www.cnblogs.com/myx12345/p/6721141.html
Copyright © 2011-2022 走看看