顯然我們可以先把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]中的最小值,那麼隨便取rk[l]~rk[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了。
奇醜無比的**如下:
varview codes: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;
vari,j,p:longint;
begin
for i:=1
to n do
begin trk[i]:=ord(s[i]);inc(sum[trk[i]]);end;
for i:=2
to255
do inc(sum[i],sum[i-1
]);
for i:=n downto1do
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 mdo
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 downto1do
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)div2;
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 downto0do
begin
while h[i]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 差異 字尾樹
題目大意 給你乙個字串 s 設 s i 是串 s 第 i 長的字尾,求 sum limits sum limits s i s j 2 times lcp s i,s j 其中 lcp x,y 表示字串 x 和字串 y 的最長公共字首 資料範圍 s 500000 最近發現字尾樹和 sam 沒學好,找...
BZOJ3238 差異(字尾自動機)
bzoj 前面的東西直接暴力算就行了 其實沒必要算的正正好 為了方便的後面的計算 我們不考慮i,j 的順序問題 也就是先求出 n i 1 nj 1 i j len i 然後對於每個字尾樹上的節點,減去一下貢獻 也就是siz e i si ze i 1 le n i len i.p aren t 這樣...
BZOJ3238 差異(字尾自動機)
bzoj 前面的東西直接暴力算就行了 其實沒必要算的正正好 為了方便的後面的計算 我們不考慮 i,j 的順序問題 也就是先求出 sum n sum n i neq j len i 然後對於每個字尾樹上的節點,減去一下貢獻 也就是 size i size i 1 len i len i.parent ...