• Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)


    E. Skyline Photo

    题意:

    (n)个元素,每个元素有两个属性(h)(b),要求把这些元素划分为若干个子区间,每个子区间的价值为该区间内(h)最小的元素的(b)的值,求最优划分使得所有子区间价值之和最大

    思路:

    考虑一个(O(n^2))(dp)(dp[i])表示前(i)个元素的答案,那么(dp[i] = max{dp[j] + val(j + 1, i) | 1 <= j < i})
    尝试优化
    (j)(i)左边第一个(h)小于(i)的下标,则(dp[i] = max{dp[k] | j <= k < i} + b[i])
    为什么不需要考虑(k<j)的情况?
    假设(x)(j)左边第一个(h)小于(j)的下标
    则当(x <= k < j)
    (dp[i] = max(max{dp[k] | x <= k < j} + b[j], max{dp[k] | j <= k < i} + b[i]))
    容易发现,前半部分就是(dp[j])
    所以(dp[i] = max(dp[j], max{dp[k] | j <= k < i} + b[i]))
    用单调栈和线段树即可

    #include<bits/stdc++.h>
    #define ls rt << 1
    #define rs rt << 1 | 1
    using namespace std;
    typedef long long ll;
    const int maxn = 300010;
    ll h[maxn], b[maxn], dp[maxn], mx[maxn << 2];
    void pushUp(int rt){
        mx[rt] = max(mx[ls], mx[rs]);
    }
    void upd(int rt, int l, int r, int pos, ll c) {
        if(l == r){
            mx[rt] += c;
            return ;
        }
        int m = (l + r) >> 1;
        if(pos <= m) upd(ls, l, m, pos, c);
        else upd(rs, m + 1, r, pos, c);
        pushUp(rt);
    }
    ll ask(int rt, int l, int r, int ql, int qr){
        if(ql <= l && r <= qr) return mx[rt];
        int m = (l + r) >> 1;
        ll ans = -1e18;
        if(ql <= m) ans = max(ans, ask(ls, l, m, ql, qr));
        if(qr > m) ans = max(ans, ask(rs, m + 1, r, ql, qr));
        return ans;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        for(int i = 1; i <= n; ++i) cin >> h[i];
        for(int i = 1; i <= n; ++i) cin >> b[i];
        dp[1] = b[1];
        vector<int>sta;
        sta.push_back(1);
        upd(1, 1, n, 1, b[1]);
        for(int i = 2; i <= n; ++i) {
            while(!sta.empty() && h[sta.back()] > h[i]) sta.pop_back();
            int l = sta.empty() ? 0 : sta.back();
            if(!l)
                dp[i] = max(ask(1, 1, n, 1, i - 1), 0ll) + b[i];
            else
                dp[i] = max(ask(1, 1, n, l, i - 1) + b[i], dp[l]);
            upd(1, 1, n, i, dp[i]);
            sta.push_back(i);
        }
        cout << dp[n] << '
    ';
        return 0;
    }
    
  • 相关阅读:
    绳关节(b2RopeJoint)
    公式推导 圆面积公式 圆周长公式
    ALTER TABLE causes auto_increment resulting key 'PRIMARY'
    MySQL通过Binlog恢复删除的表
    Barracuda VS antelope
    mysqldump 参数说明
    MySQL复制
    MySQL Server-id的作用
    MySQL 简洁连接数据库方式
    Kill 所有MySQL进程
  • 原文地址:https://www.cnblogs.com/Zeronera/p/14719522.html
Copyright © 2020-2023  润新知