本題考點:
- 優先隊列的使用
在火星上有個魔法商店,提供魔法優惠券。每個優惠劵上印有一個整數面值K,表示若你在購買某商品時使用這張優惠劵,可以得到K倍該商品價值的回報!該商店還免費贈送一些有價值的商品,但是如果你在領取免費贈品的時候使用面值爲正的優惠劵,則必須倒貼給商店K倍該商品價值的金額…… 但是不要緊,還有面值爲負的優惠劵可以用!(真是神奇的火星) 例如,給定一組優惠劵,面值分別爲1、2、4、-1;對應一組商品,價值爲火星幣M$7、6、-2、-3,其中負的價值表示該商品是免費贈品。我們可以將優惠劵3用在商品1上,得到M$28的回報;優惠劵2用在商品2上,得到M$12的回報;優惠劵4用在商品4上,得到M$3的回報。但是如果一不小心把優惠劵3用在商品4上,你必須倒貼給商店M$12。同樣,當你一不小心把優惠劵4用在商品1上,你必須倒貼給商店M$7。 規定每張優惠券和每件商品都只能最多被使用一次,求你可以得到的最大回報。
本題是優先隊列的使用經典案例,我們將正數和負數分開存放,正數放到大頂堆中,負數放到小頂堆中,然後分別從兩個堆中去除對應的值相乘然後相加即可獲得最大值。
完整代碼如下:
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
priority_queue<int> posiGoods, posiDiscounts; // 正數採用大頂堆
priority_queue<int, vector<int>, greater<int>> negaGoods, negaDiscounts; // 負數採用小頂堆
int main()
{
int n, temp;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &temp);
if (temp > 0)
posiGoods.push(temp);
else
negaGoods.push(temp);
}
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &temp);
if (temp > 0)
posiDiscounts.push(temp);
else
negaDiscounts.push(temp);
}
int sum = 0;
while (!posiGoods.empty() && !posiDiscounts.empty())
{
sum += posiGoods.top() * posiDiscounts.top();
posiDiscounts.pop();
posiGoods.pop();
}
while (!negaGoods.empty() && !negaDiscounts.empty())
{
sum += negaGoods.top() * negaDiscounts.top();
negaGoods.pop();
negaDiscounts.pop();
}
printf("%d", sum);
return 0;
}