码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2017-04-17 09:49:11      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:ring   output   题意   ansi   cti   begin   com   如何   array   

题意:

技术分享

思路:显然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.

 

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

标签:ring   output   题意   ansi   cti   begin   com   如何   array   

原文地址:http://www.cnblogs.com/myx12345/p/6721141.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!