Description
被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在3秒内解决,可见此题难度之大。
问题是这样的:n个整数围成一个环,老师要求选出其中的若干数,使得选中的数所组成的环中,两个相邻数的差的绝对值不等于1。在满足这个前提下,问最多能取多少个数。
Input
第一行一个正整数n,表示有n个数
第二行n个整数,a1、a2……an 按顺时针方向围成一个环。
Output
一个正整数,即表示最多能选多少个数。
Sample Input
5
1 2 3 5 2
Sample Output
3
Data Constraint
Hint
【样例解释】
最多能选3个数
既选择(1,3,5)或者(2,5,2)
【数据范围】
30%的数据,n≤10
50%的数据,n≤100
70%的数据,n≤1000
100%的数据,n≤100000,ai≤1100000
分析:dp(和求最长不下降子序列差不多)。然后用线段树求解。
代码:
uses math;
var
tree:array[0..1600000] of longint;
zw,wz,a,b,f:array[0..200000] of longint;
i,j,k,l,t,n,m,ans:longint;
procedure qsort(i,j:longint);
var
l,r,mid:longint;
begin
l:=i;
r:=j;
mid:=b[(i+j) div 2];
repeat
while b[i]<mid do inc(i);
while b[j]>mid do dec(j);
if i<=j then
begin
b[0]:=b[i];
b[i]:=b[j];
b[j]:=b[0];
zw[0]:=zw[i];
zw[i]:=zw[j];
zw[j]:=zw[0];
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure change(p,l,r,a,b:longint);
var
mid:longint;
begin
if l=r then
begin
tree[p]:=max(tree[p],b);
exit;
end;
mid:=(l+r) div 2;
if a<=mid then change(p*2,l,mid,a,b) else change(p*2+1,mid+1,r,a,b);
tree[p]:=max(tree[p*2],tree[p*2+1]);
end;
function get(p,l,r,a,b:longint):longint;
var
mid:longint;
begin
if (l=a)and(r=b) then exit(tree[p]);
mid:=(l+r) div 2;
if b<=mid then exit(get(p*2,l,mid,a,b))
else if a>mid then exit(get(p*2+1,mid+1,r,a,b))
else
begin
exit(max(get(p*2,l,mid,a,mid),get(p*2+1,mid+1,r,mid+1,b)));
end;
end;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]);
zw[i]:=i;
a[i+n]:=a[i];
zw[i+n]:=i+n;
end;
b:=a;
qsort(1,n*2);
t:=0;
b[0]:=b[1]-1;
for i:=1 to n*2 do
begin
if b[i]=b[i-1]+1 then inc(t)
else if b[i]>b[i-1]+1 then t:=t+2;
wz[zw[i]]:=t;
end;
m:=t;
fillchar(tree,sizeof(tree),0);
fillchar(f,sizeof(f),0);
for j:=1 to n*2 do
begin
k:=0;
if wz[j]>2 then
k:=get(1,1,m,1,wz[j]-2);
l:=0;
if wz[j]<m-1 then
l:=get(1,1,m,wz[j]+2,m);
f[j]:=max(k,l)+1;
k:=0;
k:=get(1,1,m,wz[j],wz[j]);
f[j]:=max(f[j],k+1);
change(1,1,m,wz[j],f[j]);
end;
for j:=1 to n do
if f[j]>ans then ans:=f[j];
writeln(ans div 2);
end.