2 条题解

  • 0
    @ 2026-9-3 21:07:08
    #include <queue>
    #include <vector>
    #include <cmath>
    using namespace std;
    
    typedef long long ll;
    const ll INF = 1e18;
    
    int N, M;
    ll a[100005];
    ll val[400005];
    int L[400005], R[400005];
    bool del[400005];
    
    int main() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
    
        cin >> N >> M;
        for (int i = 1; i <= N; i++) {
            cin >> a[i];
        }
    
        // 压缩:合并连续同号数为"块"
        vector<ll> blocks;
        ll cur = 0;
        bool has = false;
        for (int i = 1; i <= N; i++) {
            if (a[i] == 0) continue;
            if (!has) {
                cur = a[i];
                has = true;
            } else if ((cur > 0) == (a[i] > 0)) {
                cur += a[i];
            } else {
                blocks.push_back(cur);
                cur = a[i];
            }
        }
        if (has) blocks.push_back(cur);
    
        // 去掉首尾的负数块
        while (!blocks.empty() && blocks.front() <= 0) blocks.erase(blocks.begin());
        while (!blocks.empty() && blocks.back() <= 0) blocks.pop_back();
    
        if (blocks.empty()) {
            cout << 0 << endl;
            return 0;
        }
    
        // 统计正数块数量和总和
        int K = 0;
        ll posSum = 0;
        for (size_t i = 0; i < blocks.size(); i++) {
            if (blocks[i] > 0) {
                K++;
                posSum += blocks[i];
            }
        }
    
        if (K <= M) {
            cout << posSum << endl;
            return 0;
        }
    
        // 建双向链表 + 哨兵节点(0和n+1)
        int n = blocks.size();
        priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>> > pq;
    
        val[0] = INF;
        val[n + 1] = INF;
    
        for (int i = 1; i <= n; i++) {
            val[i] = abs(blocks[i - 1]);
            del[i] = false;
            L[i] = i - 1;
            R[i] = i + 1;
            pq.push(make_pair(val[i], i));
        }
        del[0] = false;
        del[n + 1] = false;
        R[0] = 1;
        L[n + 1] = n;
    
        // 反悔贪心:选K-M个代价最小的操作
        int nextNode = n + 2;
        ll totalCost = 0;
        int ops = K - M;
    
        for (int t = 0; t < ops; t++) {
            while (!pq.empty() && del[pq.top().second]) {
                pq.pop();
            }
            if (pq.empty()) break;
    
            pair<ll, int> top = pq.top();
            pq.pop();
            ll v = top.first;
            int i = top.second;
    
            totalCost += v;
    
            int l = L[i];
            int r = R[i];
    
            del[l] = true;
            del[i] = true;
            del[r] = true;
    
            int ll = L[l];
            int rr = R[r];
    
            // 合并节点:若以后选它 = 反悔选i,改选l和r
            int merged = nextNode++;
            val[merged] = val[l] + val[r] - v;
            del[merged] = false;
            L[merged] = ll;
            R[merged] = rr;
            R[ll] = merged;
            L[rr] = merged;
    
            pq.push(make_pair(val[merged], merged));
        }
    
        cout << posSum - totalCost << endl;
        return 0;
    }
    
    
    

    信息

    ID
    74
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    递交数
    72
    已通过
    20
    上传者