您的位置:首页 > 其它

[BZOJ3238][Ahoi2013]差异解题报告|后缀数组

2015-04-15 14:23 477 查看

Description



  先分析一下题目,我们显然可以直接算出sigma(len[Ti]+len[Tj])的值=(n-1)*n*(n+1)/2

  接着就要去算这个字符串中所有后缀的两两最长公共前缀总和

  首先可以想到后缀数组,我们计算好后缀数组之后再进行对height数组的计算

  对于以x,y开头的后缀,它们的最长公共前缀为min(height[sa[i]])(rank[x]<=i<=rank[y])

  但从以往习惯的height数组入手我们发现并没有办法解决这个问题

  不如换个角度思考,我们可以枚举这个最小的数!

  我们定义一个区间内最小的height为数值最小的情况下下标最小的位置

  那么一个数是最小的height,当且仅当这个区间的左边界到它的位置中没有数值小于等于它的数,它的右边界到它的位置中没有数值小于它的数

  我们可以用单调栈处理处这个左边界和右边界最远可以到达的位置

  然后乘法原理计算出答案就可以了

  代码写得很长的样子...(不知道为什么别人的SA好像写得都比我短...

program bzoj3238;
const maxn=500010;
var s,a,rank,sa,tmp,height,l,r,st:array[-1..maxn]of int64;
ans,n:int64;
ss:ansistring;
i:longint;

function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;

function compare(x,y,p:longint):longint;
begin
while (x+p-1<n)and(y+p-1<n)and(a[x+p-1]=a[y+p-1]) do inc(p);
exit(p-1);
end;

procedure Suffix_Array;
var i,j,p,size,v0,v1,v00,v01:longint;
begin
if n>26 then size:=n else size:=26;
for i:=0 to n-1 do rank[i]:=a[i];
for i:=0 to size-1 do s[i]:=0;
for i:=0 to n-1 do inc(s[a[i]]);
for i:=1 to size-1 do inc(s[i],s[i-1]);
for i:=n-1 downto 0 do
begin
dec(s[a[i]]);
sa[s[a[i]]]:=i;
end;
j:=1;
while j<=n do
begin
p:=0;
for i:=n-j to n-1 do
begin
tmp[p]:=i;inc(p);
end;
for i:=0 to n-1 do if sa[i]-j>=0 then
begin
tmp[p]:=sa[i]-j;inc(p);
end;
for i:=0 to size-1 do s[i]:=0;
for i:=0 to n-1 do inc(s[rank[i]]);
for i:=1 to size-1 do inc(s[i],s[i-1]);
for i:=n-1 downto 0 do
begin
dec(s[rank[tmp[i]]]);
sa[s[rank[tmp[i]]]]:=tmp[i];
end;
p:=0;tmp[sa[0]]:=0;
for i:=1 to n-1 do
begin
v0:=sa[i-1];v1:=sa[i];
if v0+j<n then v00:=rank[v0+j] else v00:=-1;
if v1+j<n then v01:=rank[v1+j] else v01:=-1;
if (rank[v0]=rank[v1])and(v00=v01) then tmp[sa[i]]:=p else
begin
inc(p);tmp[sa[i]]:=p;
end;
end;
for i:=0 to n-1 do rank[i]:=tmp[i];
j:=j << 1;
end;
end;

procedure Calc_Height;
var i:longint;
begin
if rank[0]=0 then height[0]:=0 else height[0]:=compare(0,sa[rank[0]-1],1);
for i:=1 to n-1 do
if rank[i]=0 then height[i]:=0 else height[i]:=compare(i,sa[rank[i]-1],max(height[i-1],1));
end;

procedure Solve;
var i,top:longint;
begin
height[-1]:=-maxlongint;
st[0]:=-1;sa[-1]:=-1;top:=0;
for i:=0 to n-1 do
begin
while height[sa[st[top]]]>=height[sa[i]] do dec(top);
l[i]:=st[top];
inc(top);st[top]:=i;
end;
st[0]:=n;sa
:=-1;top:=0;
for i:=n-1 downto 0 do
begin
while height[sa[st[top]]]>height[sa[i]] do dec(top);
r[i]:=st[top];
inc(top);st[top]:=i;
end;
for i:=0 to n-1 do dec(ans,height[sa[i]]*(i-l[i])*(r[i]-i)*2);
writeln(ans);
end;

begin
readln(ss);
n:=length(ss);
for i:=1 to n do a[i-1]:=ord(ss[i])-96;
for i:=1 to n do inc(ans,i*(n-1));
Suffix_Array;
Calc_Height;
Solve;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: