zoukankan      html  css  js  c++  java
  • 洛谷P3957 跳房子 题解 二分答案/DP/RMQ

    题目链接:https://www.luogu.org/problem/P3957
    这道题目我用到了如下算法:

    • 线段树求区间最大值;
    • 二分答案;
    • DP求每一次枚举答案g时是否能够找到 (ge k) 的解法。

    我们一开始用 (x[i])(s[i]) 来表示到起点的距离以及第 (i) 个点的分值。
    与此同时我们还要算上我们的起点,它满足性质 (x[0] = s[0] = 0) ,我们接下来的判断都是建立在这 (1 + n) 个点的基础上的。

    check(g)

    首先,我们假设 (g) 已经确定的情况下,如何判断是否有行走方案能够累计到 (ge k)
    这一步需要用到DP思想,我们定义状态 (f[i]) 表示从起点到第 (i) 个点所能够积累的最大分值,那么,状态转移方程为:
    (f[i] = max( f[j] )) ,其中 (j) 满足 (x[i]-d-g le x[j] le min( x[i]-1, x[i]-d+g ))
    并且我们可以发现这个范围的 (j) 必定在一个连续的区间 ([L, R]) 内,所以我们可以用二分(lower_boundupper_bound 函数来快速获得 (L)(R)
    然后我们需要知道区间 ([L,R]) 范围内 (x[j]) 的最大值,这一步过程我是使用线段树来实现的(因为这里涉及单点更新及区间最值)。

    二分答案

    在编写完 check(g) 函数之后,我们便可以在区间 ([0, x[n] ]) 范围内进行二分,进而找到满足要求的最小的答案。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 500050;
    int n, d, k, x[maxn], s[maxn], f[maxn];
    
    #define lson l, mid, (rt<<1)
    #define rson mid+1, r, (rt<<1|1)
    #define inf (1<<29)
    int maxv[maxn<<2];
    void sg_push_up(int rt) {
        maxv[rt] = max(maxv[rt<<1], maxv[rt<<1|1]);
    }
    void sg_build(int l, int r, int rt) {
        if (l >= r) maxv[rt] = -inf;
        else {
            int mid = (l + r) / 2;
            sg_build(lson);
            sg_build(rson);
            sg_push_up(rt);
        }
    }
    void sg_update(int p, int v, int l, int r, int rt) {
        if (l == r) maxv[rt] = v;
        else {
            int mid = (l + r) / 2;
            if (p <= mid) sg_update(p, v, lson);
            else sg_update(p, v, rson);
            sg_push_up(rt);
        }
    }
    int sg_query(int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) return maxv[rt];
        int mid = (l + r) / 2, tmp = -inf;
        if (L <= mid) tmp = max(tmp, sg_query(L, R, lson));
        if (R > mid) tmp = max(tmp, sg_query(L, R, rson));
        return tmp;
    }
    
    bool check(int g) {
        sg_build(0, n, 1);
        sg_update(0, 0, 0, n, 1);
        for (int i = 1; i <= n; i ++) {
            f[i] = -inf;
            int lid = lower_bound(x, x+i, x[i]-d-g) - x;
            int rid = upper_bound(x, x+i+1, min(x[i]-1, x[i]-d+g)) - x - 1;
            if (lid <= rid) {
                int tmp = sg_query(lid, rid, 0, n, 1);
                if (tmp != -inf) {
                    f[i] = tmp + s[i];
                    if (f[i] >= k) return true;
                    sg_update(i, f[i], 0, n, 1);
                }
            }
        }
        return false;
    }
    
    int main() {
        cin >> n >> d >> k;
        for (int i = 1; i <= n; i ++) cin >> x[i] >> s[i];
        int L = 0, R = x[n], res = -1;
        while (L <= R) {
            int mid = (L + R) / 2;
            if (check(mid)) { res = mid; R = mid-1; }
            else L = mid + 1;
        }
        cout << res << endl;
        return 0;
    }
    

    作者:zifeiy

  • 相关阅读:
    s3c6410时钟初始化
    一句话题解&&总结
    2019-9-2-本文说如何显示SVG
    2019-9-2-本文说如何显示SVG
    2018-8-3-WPF-读取硬件序列号
    2018-8-3-WPF-读取硬件序列号
    2018-8-10-win10-uwp-调试软件启动
    2018-8-10-win10-uwp-调试软件启动
    2018-8-10-使用-RetroShare-分享资源
    2018-8-10-使用-RetroShare-分享资源
  • 原文地址:https://www.cnblogs.com/codedecision/p/11753024.html
Copyright © 2011-2022 走看看