思路:
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;
}
}