• 「JSOI2010」挖宝藏


    「JSOI2010」挖宝藏

    传送门
    由于题目中说道挖一个位置的前提是挖掉它上面的三个,以此类推可以发现,挖掉一个点就需要挖掉这个点往上的整个倒三角,那么也就会映射到 (x) 轴上的一段区间(可以发现这种映射关系是一一对应的),那么我们就可以用一段区间来代表一个宝藏。
    然后我们就先把所有区间按照右端点递增其次左端点递增排序。
    接着考虑 ( ext{DP}) ,我们设 (dp_i) 表示前 (i) 个区间中强制选第 (i) 个区间的最大利润,
    那么在枚举转移点 (j) 时就会出现 (i)(j) 有交的情况,就会有一部分代价被多算。
    此外还有一种情况就是一个区间完全覆盖另一个的情况,这个时候如果我们选那个较大的区间肯定会顺带选了那个较小的,
    因为此时那个较小区间的代价就不用算了,所以我们可以预处理出单选一个区间的最大利润(它自己的价值以及被它覆盖的所有区间的价值之和 - 它自己的代价),
    但我们又会发现,转移时会出现 (i) , (j) 两个区间同时覆盖一个小区间,导致那个小区间的价值被算重的情况,
    所以我们干脆对于两个区间有交的情况我们暴力地去算可能被算重的价值即可,
    具体来说就是枚举到 (i) 的时候,维护一个指针指向我们需要计算的区间,因为这个指针只会右移,所以我们转移的复杂度还是 (O(n)) 的,总复杂度也就是 (O(n^2)) 的。
    如果有不懂的可以结合代码理解,还可以画图自己研究研究。
    参考代码:

    #include <algorithm>
    #include <cstdio>
    #define rg register
    #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
    using namespace std;
    template < class T > inline void read(T& s) {
        s = 0; int f = 0; char c = getchar();
        while ('0' > c || c > '9') f |= c == '-', c = getchar();
        while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
        s = f ? -s : s;
    }
     
    const int _ = 1002;
     
    int n, dp[_]; struct node { int l, r, p1, p2, c; } t[_];
    inline bool cmp(const node& x, const node& y) { return x.r != y.r ? x.r < y.r : x.l < y.l; }
     
    inline int calc(int l, int r) { return (r - l + 2) * (r - l + 2) / 4; }
     
    int main() {
    #ifndef ONLINE_JUDGE
        file("cpp");
    #endif
        read(n);
        for (rg int x, y, p, i = 1; i <= n; ++i)
            read(x), read(y), read(p), t[i] = (node) { x + y + 1, x - y - 1, p, 0, calc(x + y + 1, x - y - 1) };
        for (rg int i = 1; i <= n; ++i)
            for (rg int j = 1; j <= n; ++j)
                if (t[i].l <= t[j].l && t[j].r <= t[i].r) t[i].p2 += t[j].p1;
        sort(t + 1, t + n + 1, cmp);
        for (rg int i = 1; i <= n; ++i) {
            dp[i] = t[i].p2 - t[i].c;
            int nxt = 1, sum = 0;
            for (rg int j = 1; j < i; ++j) {
                if (t[j].r < t[i].l) dp[i] = max(dp[i], dp[j] + t[i].p2 - t[i].c);
                if (t[j].l < t[i].l && t[i].l <= t[j].r) {
                    while (nxt <= i && t[nxt].r <= t[j].r) {
                        if (t[nxt].l >= t[i].l) sum += t[nxt].p1; ++nxt;
                    }
                    dp[i] = max(dp[i], dp[j] + t[i].p2 - t[i].c - (sum - calc(t[i].l, t[j].r)));
                }
            }
        }
        int ans = 0;
        for (rg int i = 0; i <= n; ++i) ans = max(ans, dp[i]);
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    推荐系统入门笔记2--信息检索 Lucene
    Mybatis多个参数,其中有hashMap的写法
    Java中fastjson的toJSONString结果为空{}
    Linux中less命令出现ESC乱码
    关于博客
    【Uni-App】关于获取手机系统信息的项目实践
    mysql 服务列表找不到
    服务网格与Istio
    ARM架构服务器如何运行EasyNVR软件提示无法识别二进制文件排查及解决
    关于EasyNVR拉流摄像头的视频流存在视频流锁定机制的问题说明
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/12253848.html
Copyright © 2020-2023  润新知