zoj Special Subsequence 3349 (DP+线段树优化) 好题***

Time Limit: 5000MS Memory Limit: 32768KB 64bit IO Format: %lld & %llu

 Status

Description

There a sequence S with n integers , and A is a special subsequence that satisfies |Ai-Ai-1| <= d ( 0 <i<=|A|))

Now your task is to find the longest special subsequence of a certain sequence S

Input

There are no more than 15 cases , process till the end-of-file

The first line of each case contains two integer n and d ( 1<=n<=100000 , 0<=d<=100000000) as in the description.

The second line contains exact n integers , which consist the sequnece S .Each integer is in the range [0,100000000] .There is blank between each integer.

There is a blank line between two cases

Output

For each case , print the maximum length of special subsequence you can get.

Sample Input

5 2
1 4 3 6 5

5 0
1 2 3 4 5

Sample Output

3
1
//知道它是个DP,但没想到是这么屌的一个DP,看着大神的博客,愣是看了两个小时才稍微有点理解(加上找错。。。)。唉,DP这条路好难走。。。
 
//再贴代码之前先介绍一下unique()函数:
unique()函数是一个去重函数,STL中unique的函数 unique的功能是去除相邻的重复元素(只保留一个),
还有一个容易忽视的特性是它并不真正把重复的元素删除。他是c++中的函数,所以头文件要加
#include<iostream.h>,具体用法如下:
 int num[100];
 unique(num,mun+n)返回的是num去重后的尾地址,之所以说比不真正把重复的元素删除,
 其实是,该函数把重复的元素一到后面去了,然后依然保存到了原数组中,然后返回去重后
 最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 100010;
int a[N];
int b[N];
int dp[N];
int q[N<<2];
int n,d,t;
void pushu(int gen,int l,int r)
{
	q[gen]=max(q[gen<<1],q[gen<<1|1]);
}
void build(int gen,int l,int r)
{
	if(l==r)
	{
		q[gen]=0;
		return ;
	}
	int mid=(l+r)>>1;
	build(gen<<1,l,mid);
	build(gen<<1|1,mid+1,r);
	pushu(gen,l,r);
}
int query(int gen,int l,int r,int ll,int rr)
{
	if(ll<=l&&r<=rr)
	{
		return q[gen];
	}
	int mid=(l+r)>>1;
	int cnt=-1;
	if(ll<=mid)
		cnt=max(cnt,query(gen<<1,l,mid,ll,rr));
	if(rr>mid)
		cnt=max(cnt,query(gen<<1|1,mid+1,r,ll,rr));
	return cnt;
}
void update(int gen,int l,int r,int p,int v)
{
	if(l==r)
	{
		q[gen]=v;
		return ;
	}
	int mid=(l+r)>>1;
	if(p<=mid)
		update(gen<<1,l,mid,p,v);
	else
		update(gen<<1|1,mid+1,r,p,v);
	pushu(gen,l,r);
}
int main()
{
	while(scanf("%d%d",&n,&d)!=EOF)
	{
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			b[i]=a[i];
		}
		sort(b+1,b+n+1);
		int t=unique(b+1,b+n+1)-(b+1);
		memset(dp,0,sizeof(dp));
		dp[1]=1;
		build(1,1,n);
		for(int i=1;i<=n;i++)
		{
			int gen=lower_bound(b+1,b+t+1,a[i])-b;
			int l=lower_bound(b+1,b+t+1,a[i]-d)-b;
			int r=upper_bound(b+1,b+t+1,a[i]+d)-b-1;
			dp[i]=query(1,1,n,l,r)+1;
			update(1,1,n,gen,dp[i]);
		}
		int ans=-1;
		for(int i=1;i<=n;i++)
			ans=max(ans,dp[i]);
		printf("%d\n",ans);
	}
	return 0;
}

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值