环中环

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值