您的位置:首页 > 其它

环中环 纪中1347 dp+线段树优化 玄学

2016-08-16 16:47 399 查看

Description

  被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在3秒内解决,可见此题难度之大。

  问题是这样的:n个整数围成一个环,老师要求选出其中的若干数,使得选中的数所组成的环中,两个相邻数的差的绝对值不等于1。在满足这个前提下,问最多能取多少个数。

Input

  第一行一个正整数n,表示有n个数

  第二行n个整数,a1、a2……an 按顺时针方向围成一个环。

Output

  一个正整数,即表示最多能选多少个数。

分析

用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)。
输出时输出max(dp[i])。
可以用线段树来优化这一过程(范围找最大)。


代码

const
maxn=300000;

type
pnode=^tnode;
tnode=record
lc,rc:pnode;
c,xia:longint;
end;

var
f,s:array[0..maxn] of longint;
data:array[0..maxn] of longint;
ans:longint;
n,m:longint;
d:longint;
t:pnode;

procedure neww(var t:pnode);
begin
if t=nil then
begin
new(t);
t^.c:=0;
t^.lc:=nil;
t^.rc:=nil;
end;
end;

procedure insert(var t:pnode; l,r,x,y,co,xi:longint);
var
i,j,k:longint;
mid:longint;

begin
with t^ do
begin
if c<co
then
begin
c:=co;
xia:=xi;
end;
mid:=(l+r) div 2;
if (l=x) and (r=y)
then
exit;
if (l<=x) and (mid>=y)
then
begin
neww(lc);
insert(lc,l,mid,x,y,co,xi);
exit;
end;
if (mid<x) and (r>=y)
then
begin
neww(rc);
insert(rc,mid+1,r,x,y,co,xi);
exit;
end;
neww(lc);
neww(rc);
insert(lc,l,mid,x,mid,co,xi);
insert(rc,mid+1,r,mid+1,y,co,xi);
end;
end;

function find(t:pnode;l,r,x,y:longint; var x1:longint):longint;
var
mid:longint;
i,j,k:longint;
begin
if t=nil then exit(0);
if l>r then exit(0);
with t^ do
begin
mid:=(l+r) div 2;
if (l=x) and (r=y)
then
begin
find:=c;
x1:=xia;
exit;
end;
i:=0;
j:=0;
if (l<=x) and (mid>=y)
then
begin
find:=find(lc,l,mid,x,y,x1);
exit;
end;
if (mid<x) and (r>=y)
then
begin
find:=find(rc,mid+1,r,x,y,x1);
exit;
end;
i:=find(lc,l,mid,x,mid,x1);
k:=0;
j:=find(rc,mid+1,r,mid+1,y,k);
if i>j
then
find:=i
else
begin
find:=j;
x1:=k;
end;
end;
end;

procedure init;
var
i:longint;
begin
readln(n);
m:=0;
for i:=1 to n do
begin
read(data[i]);
data[i+n]:=data[i];
if data[i]>m then m:=data[i];
end;
end;

function max(x,y:longint):longint;
begin
if x>y then exit(x)
else exit(y);
end;

procedure main;
var
i,j,k,l:longint;
x,y,z:longint;
ans:longint;
begin
neww(t);
insert(t,1,m,data[1],data[1],1,1);
f[1]:=1;
s[1]:=1;
for i:=2 to n do
begin
x:=0; y:=0; z:=0;
j:=find(t,1,m,1,data[i]-2,x);
k:=find(t,1,m,data[i]+2,m,y);
l:=find(t,1,m,data[i],data[i],z);
f[i]:=max(j,k);
f[i]:=max(f[i],l);
if f[i]=j
then s[i]:=x
else if f[i]=k then s[i]:=y
else s[i]:=z;
if f[i]=0 then s[i]:=i;
f[i]:=f[i]+1;
insert(t,1,m,data[i],data[i],f[i],s[i]);
end;
ans:=0;
for i:=1 to n do
if (ans<f[i]) and (abs(data[s[i]]-data[i])<>1) then ans:=f[i];
write(ans);
end;

begin
init;
main;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: