【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.
null