您的位置:首页 > 产品设计 > UI/UE

ZOJ 3349 Special Subsequence【dp+线段树优化】

2017-08-08 09:44 337 查看
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\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: