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;
    }
    
    
    
    • -9
      @ 2024-2-1 16:53:31
      **#**include** **<algorithm>
      **#**include** **<queue>
      **#**include** **<vector>
      using namespace std**;**
      **const**  **int** N**=**100010**;**
      **typedef** pair**<**int **,**int **>** PII**;**
      **int** a**[**N**]**;
      **int** l**[**N**]**,r**[**N**]**;**//链表中标记左右位置的数组**
      **int** n**,**m**;**
      bool st**[**N**]**;**//当弹出某一位置元素时,可能会影响到其他位置的元素的选择情况**
      **void** **remove**(**int** p**)**
      **{**
      	l**[**r**[**p**]**]**=**l**[**p**]**;
      	r**[**l**[**p**]**]**=**r**[**p**]**;
      	st**[**p**]**=true**;**
      **}**
      **int** **main**(**)**
      **{**
      	cin**>>**n**>>**m**;**
      	**int** k**=**1**;**
      	**for**(**int** i**=**1**;**i**<=**n**;**i**++**)
      	**{**
      		**int** x**;**
      		cin**>>**x**;**
      		**if**(**(**long **long** **)**a**[**k**]***x**<**0**)**a**[**++k**]**=x**;**//将相邻且相同符号的元素合并
      		**else** a**[**k**]**+**=**x**;**
      	**}**
          
          **int** cnt**=**0**,**res**=**0**;**
          priority_queue**<**PII**,**vector**<**PII **>** **,**greater**<**PII **>** **>**heap**;**
          n**=**k**;**//将合并后的边界更新
          **for**(**int** i**=**1**;**i**<=**k**;**i**++**)
          **{**
          	l**[**i**]**=i**-**1**;**
          	r**[**i**]**=i**+**1**;**//初始化相邻数组
              **if**(a**[**i**]**>**0**)
              **{**//首先我们得到所有正数的和,即最大值
              	cnt**++**;
              	res**+**=a**[**i**]**;
              **}**
              heap**.**push**(**{**abs**(a**[**i**]**)**,**i**}**)**;**
          **}**
      
          **while**(cnt**>**m**)**
          **{**//当我们选中的所有正数的个数(即连续的正数序列的个数)超过要求时
          	**//我们就要在其中有选择的去除一些**
          	**while**(st**[**heap**.**top**(**)**.**second**]**)heap**.**pop**(**)**;**
          	**//当我们堆顶元素位置被标记为删除时,我们在小顶堆中将其删除**
          	**auto** t**=**heap**.**top**(**)**;**
          	heap**.**pop**(**)**;**//我们获得当前绝对值最小的元素,将其删除
      
              **int** v**=**t**.**first**,**p**=**t**.**second**;**
              **int** left**=**l**[**p**]**,right**=**r**[**p**]**;
              **if**(left**>**0**&&**right**<**n**+**1**||**a**[**p**]**>**0**)
              **{**
              	cnt**--**;
              	res**-**=v**;**
              	a**[**p**]**+**=**a**[**left**]**+a**[**right**]**;
              	**remove**(left**)**;
              	**remove**(right**)**;
              	heap**.**push**(**{**abs**(a**[**p**]**)**,**p**}**)**;**
              **}**
          **}**
         cout**<<**res**<<**endl**;**
         **return** **0**;
      **}**
      
      • @ 2025-4-12 17:46:29

        防伪吗,有点意思

    • 1

    信息

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