MT3032 环形喂猪

思路:

1.输出Error的情况:m>n/2 

2.首先将饥饿值放到大根堆中,先喂最饿的猪i,则把i的饥饿值加到sum中;但也又可能喂i-1和i+1,所以此时需要反悔:把i取出来的同时,将a[i-1]+a[i+1]-a[i]放入堆中。(即保留取i,也保留取i-1和i+1的可能性),此时将i-1,i,i+1合并为一个节点

#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 10;
int n, m, l[N], r[N], ans, a[N], tot;
bool mark[N];
struct node
{
    int id, v; // v为饥饿值
    bool operator<(const node &a) const
    { // 使用大根堆,重载<号
        return v < a.v;
    }
} tmp;
priority_queue<node> q; // 大根堆
int main()
{
    cin >> n >> m;
    if (m > n / 2)
    {
        cout << "Error!";
        return 0;
    }

    else
    {
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 2; i < n; i++)
        { // 处理链表
            l[i] = i - 1, r[i] = i + 1;
            q.push({i, a[i]});
        }
        // 处理环形(使用链表存储)
        l[1] = n, r[1] = 2;
        l[n] = n - 1, r[n] = 1;
        q.push({1, a[1]});
        q.push({n, a[n]});
        tot = n;
        for (int i = 1; i <= m; i++)
        {
            tmp = q.top(); // 取出堆头节点放入tmp中
            q.pop();
            if (mark[tmp.id])
            { // 如果已经被标记,即若取i,则标记i-1和i+1表示不能被取
                i--;
                continue;
            }
            ans += tmp.v; // 没被标记,则加到答案中
            // 新增节点
            a[++tot] = a[l[tmp.id]] + a[r[tmp.id]] - a[tmp.id];
            q.push({tot, a[tot]}); // 合并成一个节点
            // 更新链表中左右指针位置关系
            // 因为取了i就不能取i-1和i+1,所以位置关系类似
            //  i-2 tot i+2    tot为i-1 i i+1  tmp为i
            l[tot] = l[l[tmp.id]]; // tot左边为i-2,即tmp的l的l
            r[l[l[tmp.id]]] = tot; // i-2的右边为tot
            r[tot] = r[r[tmp.id]]; // tot右边为i+2,即tmp的r的r
            l[r[r[tmp.id]]] = tot; // i+2的左边为tot
            // 将这三个节点标记为已被处理
            mark[tmp.id] = mark[l[tmp.id]] = mark[r[tmp.id]] = 1;
        }
        cout << ans;
        return 0;
    }
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值