#贪心 #优先队列
问题描述:
给定n 副卡牌,每张卡牌具有正反面,正面朝上数字为 ai,背面朝上数字为 bi。一副卡牌的价值为正面朝上数字之和。一开始所有卡牌都是正面朝上的。小蓝是蓝桥学院最优秀的魔法师,他知道所有卡牌的背面数字 bi,他最多可以进行 k 次操作,每次可以将一副卡牌翻转,将正面朝上的数字变为背面朝上的数字,或将背面朝上的数字变为正面朝上的数字。请问,小蓝最多可以使卡牌的价值之和为多少?
输入格式:
第一行输入两个整数 n 和 k ,表示卡牌的数量和小蓝可以操作的次数。
第二行输入 n 个整数 ai ,表示所有卡牌正面的数字。
第三行输入 n 个整数 bi ,表示所有卡牌反面的数字。
数据范围保证:
1 ≤ n ≤ 1×10^5 ,
1 ≤ ai,bi ,k ≤ 10^9
输出格式:
输出一个整数,表示可以得到的卡牌的最大价值和。
样例输入:
3 1
1 2 3
3 2 1
样例输出:
8
样例说明:
将第一张卡牌翻转,此时卡牌的总和为 3 + 2 + 3 = 8 。
题解:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll n = 1e5 + 9;
ll a[n], b[n];
priority_queue<ll, vector<ll>, less<ll>>pq;
int main() {
ll n, k;
ll ans = 0;
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
ans += a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
for (int i = 1; i <= n; i++) {
pq.push(b[i] - a[i]);
}
while (k-- && !pq.empty()) {
if (pq.top() > 0)
ans += pq.top();
pq.pop();
}
cout << ans << endl;
return 0;
}
总结:
首先定义两个数组,用来存放卡牌的正面和卡牌的反面。
定义一个优先队列用于记录卡牌正反面的差值,less< ll >,表示采用大顶堆的排序顺序,即队列由大到小进行排列。再将差值加到 ans 中,ans 即为最大的卡牌价值 。
本题也可采用小顶堆的方式,即less< ll >。