ZOJ 3349 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

Author: CHEN, Zhangyi
Contest: ZOJ Monthly, June 2010


题目:给出一个序列,找出一个最长的子序列,相邻的两个数的差在d以内。

很容易想到用dp (dp[i]=max(dp[j])+1)表示i从满足abs(a[i]-a[j])<=d的j所转移过来的最大值,每次维护这个最大值递推即可,复杂度为o(n^2)

可以用线段树优化,用线段树处理出区间l到r的max(dp[j])然后进行状态转移,为o(nlogn)

因为a[i]很大,所以要先进行坐标离散化处理再进行计算。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#define INF 0x3f3f3f3f
#define ms(x,y) memset(x,y,sizeof(x))
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;

const int maxn = 1e5 + 5;
const int mod = 998244353;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int s[maxn];
int san[maxn], tot;
int sum[maxn << 2];

void pushUp(int rt) 
{
	sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]);
}

void update(int pos, int c, int l, int r, int rt) 
{
	if (l == r) 
	{
		sum[rt] = c;
		return;
	}
	int m = (l + r) >> 1;
	if (pos <= m) update(pos, c, lson);
	else update(pos, c, rson);
	pushUp(rt);
}

int query(int L, int R, int l, int r, int rt) 
{
	if (L <= l && R >= r) 
	{
		return sum[rt];
	}
	int m = (l + r) >> 1;
	int ret = 0;
	if (L <= m) ret = query(L, R, lson);
	if (R > m) ret = max(ret, query(L, R, rson));
	return ret;
}

int main() 
{
	int n, d;
	while (~scanf("%d%d", &n, &d)) 
	{
		for (int i = 0; i < n; ++i)
		{
			scanf("%d", &s[i]);
			san[i] = s[i];
		}

		tot = n;
		sort(san, san + tot);
		tot = unique(san, san + tot) - san;

		ms(sum, 0);
		int ans = 0;

		for (int i = 0; i < n; i++) 
		{

			//本来是
			//	l=lower_bound(san, san + tot, s[i] - d) - san
			//	r = upper_bound(san, san + tot, s[i] + d) - san - 1;
			//因为线段树维护1~n的区间,而l与r是从0开始的,所以统一向右移一位

			int pos = lower_bound(san, san + tot, s[i]) - san + 1;
			int l = lower_bound(san, san + tot, s[i] - d) - san + 1;
			int r = upper_bound(san, san + tot, s[i] + d) - san;
			int que = query(l, r, 1, tot, 1) + 1;	//dp[i]=max(dp[j]0+1  (a[j] >= a[i] - d && a[j] <= a[i] + d)

			ans = max(ans, que);

			update(pos, que, 1, tot, 1);
		}
		printf("%d
", ans);
	}
	return 0;
}


Fighting~
原文地址:https://www.cnblogs.com/Archger/p/8451605.html