hdu 4521(dp+线段树)

来源:互联网 发布:中国海洋大学 知乎 编辑:程序博客网 时间:2024/06/14 18:43

题意:求长度为n的序列中,间隔至少为d的最长上升子序列的长度。
题解:因为n取值到1e5,到每个元素之前的最长上升子序列用线段树维护,区间内的值是在当前区间内最长上升子序列的最大长度,区间范围是给出的序列中的值确定的,f[i]存从0到a[i]的范围内的最长上升子序列的最大长度,因为间隔要大于等于d,所以第i个元素进行线段树更新节点后,f数组只更新到i-d。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 100005;int n, d, a[N], f[N], tree[N << 2];int query(int k, int left, int right, int l, int r) {    if (l <= left && right <= r)        return tree[k];    int mid = (left + right) / 2;    if (mid >= r)        return query(k * 2, left, mid, l, r);    if (mid < l)        return query(k * 2 + 1, mid + 1, right, l, r);    return max(query(k * 2, left, mid, l, mid), query(k * 2 + 1, mid + 1, right, mid + 1, r));}void modify(int k, int left, int right, int pos, int x) {    if (left == right) {        tree[k] = max(tree[k], x);        return;    }    int mid = (left + right) / 2;    if (pos <= mid)        modify(k * 2, left, mid, pos, x);    else        modify(k * 2 + 1, mid + 1, right, pos, x);    tree[k] = max(tree[k * 2], tree[k * 2 + 1]);}int main() {    while (scanf("%d%d", &n, &d) == 2) {        memset(tree, 0, sizeof(tree));        for (int i = 1; i <= n; i++)            scanf("%d", &a[i]);        int res = 0;        for (int i = 1; i <= n; i++) {            if (a[i] > 0)                res = max(res, f[i] = query(1, 0, N, 0, a[i] - 1) + 1);            else                res = max(res, f[i] = 1);            if (i - d > 0)                modify(1, 0, N, a[i - d], f[i - d]);        }        printf("%d\n", res);    }    return 0;}
0 0
原创粉丝点击