[bzoj3238]差异(后缀数组+单调栈)
Posted Sakits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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]中的最小值,那么在l~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.
以上是关于[bzoj3238]差异(后缀数组+单调栈)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3238差异[AHOI2013](后缀数组+单调栈)