首页 > 其他分享 >Educational Codeforces Round 143 (Rated for Div. 2)

Educational Codeforces Round 143 (Rated for Div. 2)

时间:2023-02-17 22:13:35浏览次数:41  
标签:std Educational Rated 143 int auto back st res

E. Explosions?

题目抽象为现有长度为 \(n\) 的数组 \(a_1,a_2,\cdots,a_n\) \((1\le a_i\le 10^{6})\)。

定义满足以下条件的区间 \([l,r]\) \((1\le l,r\le n)\) 为爆炸区间:
\(\exists i\in [l,r]\) 使得 \(a\) 在 \([l,i]\) 严格单调递增,\(a\) 在 \([i,r]\) 严格单调递减。

设定 \([l,r]\) 为爆炸区间,\(i\) 满足 \(a_i=\max\limits_{j=l}^{r}a_j\) 为爆炸点。

每次操作可以选一个 \(a_i\) \((a_i> 0)\) 减 \(1\),代价为 \(1\),在任意次操作后满足 \(a_i=0\) \((i\notin [l,r])\),并且 \([l,r]\) 为爆炸区间,那么可以花费代价 \(\max\limits_{i=l}^{r}a_i\) 将该区间的所有数减为 \(0\),求将该数组全部清零的最小代价。

那么我们枚举 \(i\) 作为爆炸点,记 \([p,q]\) 为以 \(i\) 作为爆炸点的爆炸区间,求出最大的 \((\sum\limits_{j=p}^{q}a_j)-a_i\),记为 \(x\),那么 \((\sum\limits_{j=1}^{n}a_j)-x\) 就是答案。

选择一个数作为爆炸点那么这个数肯定不执行减 \(1\) 操作,将 \(a\) 跑两次单调栈,是一个不严格单调递增栈(单调不递减栈),先正着跑,这样可以跑出 \(i\) 只向左爆炸最多能照成多少伤害,翻转 \(a\) 再跑一次,这样可以跑出 \(i\) 只向右爆炸最多能造成多少伤害。

C++ Code
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n;
    std::cin >> n;

    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }

    auto work = [&](auto &a) {
        auto b = a;
        for (int i = 0; i < n; i++) {
            b[i] -= i;
        }

        std::vector<i64> res(n);
        std::vector<int> st;

        for (int i = 0; i < n; i++) {
            while (!st.empty() && b[st.back()] > b[i]) {
                st.pop_back();
            }
            if (!st.empty() && a[i] - (i - st.back()) >= 0) {
                int d = i - st.back();
                res[i] = res[st.back()] + 1LL * d * (a[i] + a[i] - d + 1) / 2;
            } else {
                int d = std::min(i + 1, a[i] + 1);
                res[i] = 1LL * d * (a[i] + a[i] - d + 1) / 2;
            }
            st.push_back(i);
        }

        return res;
    };

    auto l = work(a);
    reverse(a.begin(), a.end());
    auto r = work(a);
    reverse(r.begin(), r.end());
    reverse(a.begin(), a.end());
    
    i64 ans = 0;
    for (int i = 0; i < n; i++) {
        ans = std::max(ans, l[i] + r[i] - 2 * a[i]);
    }
    
    i64 sum = std::accumulate(a.begin(), a.end(), 0LL);
    std::cout << sum - ans << '\n';
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t = 1;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

标签:std,Educational,Rated,143,int,auto,back,st,res
From: https://www.cnblogs.com/kiddingma/p/17131611.html

相关文章