后缀数组Pascal代码实现

以前不会想,也不会写。现在会写了,也大概想明白了。后缀数组,真是个麻烦的东西。

题目大意如下:给定一个长度在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.

你可能感兴趣的:(pascal)