题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
1.长度至少为5个音符。
2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)
3.重复出现的同一主题不能有公共部分。
二分答案长度为k,然后用SA判断是否符合情况,每个height<k
且sa之间的距离一定要大于k。
打了半天一直WA,结果最后发现是清空的时候要全部清空不是只清空n以内的= =,醉了。
//uses math;
var
l,r,mid,i,j,k,p,n,m,ans:longint;
s,b,c,d,sa,rank,height:Array[0..400005]of longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x)
else exit(y);
end;
function min(x,y:longint):longint;
begin
if x<y then exit(x)
else exit(y);
end;
procedure getsa(m:longint);
var
i,j,t:longint;
begin
for i:=0 to m do b[i]:=0;
for i:=1 to n do inc(b[s[i]]);
for i:=1 to m do b[i]:=b[i]+b[i-1];
for i:=n downto 1 do
begin
c[b[s[i]]]:=i;
dec(b[s[i]]);
end;
t:=0;
for i:=1 to n do
begin
if s[c[i]]<>s[c[i-1]]then inc(t);
rank[c[i]]:=t;
end;
j:=1;
while j<=n do
begin
for i:=0 to n do b[i]:=0;
for i:=1 to n do inc(b[rank[i+j]]);
for i:=1 to n do b[i]:=b[i]+b[i-1];
for i:=n downto 1 do
begin
c[b[rank[i+j]]]:=i;
dec(b[rank[i+j]]);
end;
for i:=0 to n do b[i]:=0;
for i:=1 to n do inc(b[rank[i]]);
for i:=1 to n do b[i]:=b[i]+b[i-1];
for i:=n downto 1 do
begin
d[b[rank[c[i]]]]:=c[i];
dec(b[rank[c[i]]]);
end;
t:=0;
for i:=1 to n do
begin
if (rank[d[i]]<>rank[d[i-1]])or
((rank[d[i]]=rank[d[i-1]])and(rank[d[i]+j]<>rank[d[i-1]+j]))then inc(t);
c[d[i]]:=t;
end;
for i:=1 to n do rank[i]:=c[i];
if t=n then break;
j:=j*2;
end;
for i:=1 to n do sa[rank[i]]:=i;
end;
procedure getheight;
var
i,j,t,k:longint;
begin
k:=0;
for i:=1 to n do
begin
if k<>0 then dec(k);
j:=sa[rank[i]-1];
while (i+k<=n)and(j+k<=n)and(s[i+k]=s[j+k])do inc(k);
height[rank[i]]:=k;
end;
end;
function check(k:longint):boolean;
var
i,j,mn,mx:longint;
begin
mn:=maxlongint;
mx:=0;
for i:=1 to n do
begin
if height[i]<k then
begin
mn:=maxlongint;
mx:=0;
continue;
end;
mn:=min(mn,min(sa[i],sa[i-1]));
mx:=max(mx,max(sa[i],sa[i-1]));
if mx-mn>k then exit(true);
end;
exit(false);
end;
begin
while true do
begin
readln(n);
if n=0 then break;
for i:=0 to 400000 do
begin
sa[i]:=0;
rank[i]:=0;
height[i]:=0;
end;
for i:=1 to n do read(s[i]);
for i:=1 to n-1 do s[i]:=s[i]-s[i+1]+100;
s[n]:=0;
getsa(200);
getheight;
l:=4;
r:=n;
ans:=0;
while l<=r do
begin
mid:=(l+r)div 2;
if check(mid) then
begin
ans:=mid+1;
l:=mid+1;
end
else r:=mid-1;
end;
writeln(ans,' ');
end;
end.