Special Subsequence(离散化线段树+dp)

Special Subsequence

Time Limit: 5 Seconds      Memory Limit: 32768 KB

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

题解:让求|Ai-Ai-1| <= d 的最长子序列;
很简单就想到DP;
dp[i]表示前i个数的最长为多少,
则dp[i]=max(dp[j]+1) abs(a[i]-a[j])<=d
不出意外,肯定超时了;
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
typedef long long LL;
#define mem(x,y) memset(x,y,sizeof(x))
#define PI(x) printf("%d",x)
#define PL(x) printf("%lld",x)
#define SI(x) scanf("%d",&x)
#define SL(x) scanf("%lld",&x)
#define P_ printf(" ")
#define T_T while(T--)
const int MAXN=100010;
int dp[MAXN];
int m[MAXN];
int main(){
	int n,d;
	while(~scanf("%d%d",&n,&d)){
		for(int i=0;i<n;i++)SI(m[i]);
		mem(dp,0);
		int ans=0;
		for(int i=0;i<n;i++){
			for(int j=0;j<i;j++){
				if(abs(m[i]-m[j])<=d){
					dp[i]=max(dp[i],dp[j]+1);
					ans=max(ans,dp[i]);
				}
			}
		}
		printf("%d
",ans+1);
	}
	return 0;
}

 

接下来就是如何高效地找到满足差值在d以内的最大值。

将数字进行离散化,对于一个新的数,就可以确定一个范围,然后在这个范围进行查找dp的最值+1即可。

线段树每一个结点保存的是这个区间的最值,叶子结点的值便是以这个数结尾的最长数量;

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
typedef long long LL;
#define mem(x,y) memset(x,y,sizeof(x))
#define PI(x) printf("%d",x)
#define PL(x) printf("%lld",x)
#define SI(x) scanf("%d",&x)
#define SL(x) scanf("%lld",&x)
#define P_ printf(" ")
#define T_T while(T--)
#define ll root<<1
#define rr root<<1|1
#define lson ll,l,mid
#define rson rr,mid+1,r
#define V tree[root]
const int MAXN=100010;
int tree[MAXN<<2];
int a[MAXN],b[MAXN];
int dp[MAXN];
int nm;
int pushup(int root){
	tree[root]=max(tree[ll],tree[rr]);
}
void update(int root,int l,int r,int nt,int v){
	int mid=(l+r)>>1;
	if(l==r){
		V=v;return;
	}
	if(mid>=nt)update(lson,nt,v);
	else update(rson,nt,v);
	pushup(root);
}
void query(int root,int l,int r,int L,int R){
	if(l>=L&&r<=R){
		nm=max(nm,V);
		return;
	}
	int mid=(l+r)>>1;
	if(mid>=L)query(lson,L,R);
	if(mid<R)query(rson,L,R);
}
int main(){
	int n,d;
	while(~scanf("%d%d",&n,&d)){
		for(int i=0;i<n;i++)SI(a[i]),b[i]=a[i];
		sort(b,b+n);
		mem(tree,0);mem(dp,0);
		for(int i=0;i<n;i++){
			int l,r;
			l=lower_bound(b,b+n,a[i]-d)-b+1;
			r=upper_bound(b,b+n,a[i]+d)-b+1-1;
			nm=0;
			query(1,1,n,l,r);
			dp[i]=nm+1;
			update(1,1,n,lower_bound(b,b+n,a[i])-b+1,dp[i]);
		}
		int ans=0;
		for(int i=0;i<n;i++)ans=max(ans,dp[i]);
		printf("%d
",ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/handsomecui/p/5037473.html