您的位置:首页 > 其它

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

2017-04-17 07:20 211 查看

题意:

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

:=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 :=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.

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: