以前不会想,也不会写。现在会写了,也大概想明白了。后缀数组,真是个麻烦的东西。
题目大意如下:给定一个长度在5000以内的字符串,求出出现过两次或两次以上的最长字串(保证唯一解)。
不多说了,裸的后缀数组:
Program Suffix;//By_Thispoet
Const
maxn=10000;
Var
i,j,k,m,n,p,q,ans,pos,sum :Longint;
rank,sa,a,x,y :Array[1..maxn]of Longint;
st :Ansistring;
Procedure Qsort(l,r:Longint);
var i,j,k,p,temp:Longint;
begin
i:=l;j:=r;k:=x[(i+j)>>1];p:=y[(i+j)>>1];
repeat
while (x[i]<k)or((x[i]=k)and(y[i]<p)) do inc(i);
while (x[j]>k)or((x[j]=k)and(y[j]>p)) do dec(j);
if i<=j then
begin
temp:=x[i];x[i]:=x[j];x[j]:=temp;
temp:=y[i];y[i]:=y[j];y[j]:=temp;
temp:=sa[i];sa[i]:=sa[j];sa[j]:=temp;
inc(i);dec(j);
end;
until i>j;
if i<r then Qsort(i,r);
if l<j then Qsort(l,j);
end;
BEGIN
readln(st);
n:=length(st);
p:=1;
for i:=1 to n do rank[i]:=ord(st[i])-64;
while p<=n-1 do
begin
for i:=1 to n do x[i]:=rank[i];
for i:=1 to n do y[i]:=rank[i+p];
for i:=1 to n do sa[i]:=i;
Qsort(1,n);
sum:=1;
rank[sa[1]]:=1;
for i:=2 to n do
begin
if (x[i]<>x[i-1])or(y[i]<>y[i-1]) then inc(sum);
rank[sa[i]]:=sum;
end;
if sum=n then break;
p:=p << 1;
end;
for i:=2 to n do
begin
p:=sa[i];q:=sa[i-1];
j:=0;
while (p<=n)and(q<=n)and(st[p]=st[q]) do
begin
inc(j);
inc(p);inc(q);
end;
if j>ans then
begin
ans:=j;
pos:=p-1;
end;
end;
writeln(ans);
for i:=pos-ans+1 to pos do write(st[i]);
writeln;
END.