题目描述
被认为天才的小头遇到麻烦了!!这天数学课老师给出了一道难题,而小头居然没能在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);
}
1347

被折叠的 条评论
为什么被折叠?



