Description
被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在3秒内解决,可见此题难度之大。
问题是这样的:n个整数围成一个环,老师要求选出其中的若干数,使得选中的数所组成的环中,两个相邻数的差的绝对值不等于1。在满足这个前提下,问最多能取多少个数。
Input
第一行一个正整数n,表示有n个数
第二行n个整数,a1、a2……an 按顺时针方向围成一个环。
Output
一个正整数,即表示最多能选多少个数。
题解
需要发现一个性质。即枚举完起点把环转化成一行后,用dp[i]表示以第i个数结尾最多能选多少个数,那么在求dp[i]时只需要记录dp[1]到dp[i-1]里前3大的数就可以了(显然3个不同数中至少有一个和a[i]的绝对值不等于1)。同理,在枚举起点时也只要枚举前5个不同的数。因此该题复杂度为O(N)。
但本人笨,不会。于是在用LXF的方法做对。
用dp[i]表示以第i个数结尾最多能选多少个数。
那我们只能在dp[1]..d[i-1]的范围中找到一个最大的dp[j],且a[j]是在 0..a[i]-2,a[i],a[i]+2..max的范围中(因为a[i]-1和a[i]+1与a[i]的差的绝对值等于1)。
可以把原队列复制一次在队尾,把数的个数变成n*2,就可以处理环的最后一个数和第一个数是否冲突。
输出时输出max(dp[i]) div 2。
可以用线段树来优化这一过程(范围找最大)。
最后,我在此吐槽一句,后面的方法是水解。因为数据太水。我的代码不能处理(3,3,3,3,6,6,6,2,2,4,4)结果是7,而我的是9。希望大家能告诉我那错了。
代码
type
arr=record
nm,w:longint;
end;
var
ans,n,m:longint;
t:array [0..400001] of longint;
f,h:array [0..200001] of longint;
a:array [0..200001] of arr;
function max(o,p:longint):longint;
begin
if o>p then exit(o)
else exit(p);
end;
function ins(p,x,y,l,r:longint):longint;
var
mid:longint;
begin
if (x=l) and (y=r) then exit(t[p]);
mid:=(l+r) div 2;
if y<=mid then exit(ins(p*2,x,y,l,mid)) else
if mid+1<=x then exit(ins(p*2+1,x,y,mid+1,r)) else
exit(max(ins(p*2,x,mid,l,mid),ins(p*2+1,mid+1,y,mid+1,r)));
end;
procedure count(x,y,l,r,sum:longint);
var
mid:longint;
begin
if l=r then
begin
t[x]:=max(t[x],sum);
exit;
end;
mid:=(l+r) div 2;
if y<=mid then count(x*2,y,l,mid,sum)
else count(x*2+1,y,mid+1,r,sum);
t[x]:=max(t[x*2],t[x*2+1]);
end;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l; j:=r;
mid:=a[(l+r) div 2].nm;
repeat
while a[i].nm<mid do inc(i);
while a[j].nm>mid do dec(j);
if i<=j then
begin
a[0]:=a[i]; a[i]:=a[j]; a[j]:=a[0];
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure main;
var
i,x,y,z:longint;
begin
fillchar(f,sizeof(f),0);
for i:=1 to n*2 do
begin
if h[i]-2>0 then x:=ins(1,1,h[i]-2,1,m)
else x:=0;
if h[i]+2<m+1 then y:=ins(1,h[i]+2,m,1,m)
else y:=0;
z:=ins(1,h[i],h[i],1,m);
f[i]:=max(max(x,y),z)+1;
count(1,h[i],1,m,f[i]);
end;
ans:=0;
for i:=1 to n*2 do
ans:=max(f[i],ans);
end;
procedure init;
var
i:longint;
begin
readln(n);
for i:=1 to n do
begin
read(h[i]);
h[i+n]:=h[i];
end;
for i:=1 to n<<1 do
begin
a[i].nm:=h[i];
a[i].w:=i;
end;
qsort(1,n*2);
m:=1;
h[a[1].w]:=m;
for i:=2 to n<<1 do
begin
if abs(a[i].nm-a[i-1].nm)=1 then inc(m) else
if a[i].nm<>a[i-1].nm then inc(m,2);
h[a[i].w]:=m;
end;
end;
begin
init;
main;
write(ans div 2);
end.