[DP][线段树]环中环

题目描述

被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在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
设fi为选择第i个数时,最多能选得数
那么易得fi=max{fj(aj±1≠ai)
我们可以考虑使用一棵二分树来维护f,这样我们只需要寻找0~ai-2 ai+2~1100000 和ai~ai(即找自己)即可
同时因为这题是环,所以哪个作为起点都行,那么我们把数列翻倍,易知答案除以2就是原环的答案(相当于double了一个环)

#include <iostream>
#include <cstdio>
#define rep(i,a,b) for (i=a;i<=b;i++)
#define q(x) tree[x]
using namespace std;
int n,i;
int a[200001];
int f[200001],tree[4400001];
void change(int p,int l,int r,int d)
{
    if (l==r)
    {
        q(p)=f[i];
        return;
    }
    int mid=(l+r)/2;
    if (d<=mid) change(p*2,l,mid,d);
    else change(p*2+1,mid+1,r,d);
    q(p)=max(q(p*2),q(p*2+1));
}
int ask(int p,int x,int y,int l,int r)
{
    if (r<0||l>1100000) return 0;
    int val=0;
    if (x==l&&y==r)
    return q(p);
    int mid=(x+y)/2;
    if (r<=mid) val=ask(p*2,x,mid,l,r);
    else
    if (mid<l) val=ask(p*2+1,mid+1,y,l,r);
    else
    {
        val=ask(p*2,x,mid,l,mid);
        val=max(val,ask(p*2+1,mid+1,y,mid+1,r));
    }
    return val;
}
int main()
{
    scanf("%d",&n);
    rep(i,1,n)
    {
        scanf("%d",&a[i]);
        a[i+n]=a[i];
    }
    rep(i,1,2*n)
    {
        f[i]=max(ask(1,0,1100000,a[i]+2,1100000),
        max(ask(1,0,1100000,0,a[i]-2),
        ask(1,0,1100000,a[i],a[i])))+1;
        change(1,0,1100000,a[i]);
    }
    printf("%d",q(1)/2);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值