HDU 6438 Buy and Resell CCPC网络赛(贪心)
题意 : 给出一些数、你可以从左到右对这些数进行三种操作花费 Ai 买入东西、以 Ai 价格卖出你当前有的东西、或者什么都不做、现在问你可以获取的最大利益是多少?
分析:和CF 867E差不多
对于每个元素产生的贡献
可以先算出暂时的最优值
如果下次碰到更优的选择再进行替换
具体就是首先使用小顶堆维护枚举过的元素
然后对于当前枚举到的元素
用它和堆顶元素做对比、如果小于或等于堆顶元素
那么它无法和之前枚举过的所有元素的任何一个做减法产生贡献
所以将其加入这个小顶堆当中去
如果大于堆顶元素、则用它和堆顶元素做减法、算出它和堆顶元素产生贡献
当然这个贡献只是暂时最优的、堆顶元素和当前枚举到的元素进行配对并不一定是最优的
那么怎么样在下一次枚举到更优的配对元素时进行替换
答案就是做完贡献之后、将堆顶元素弹出、然后 push 两次当前枚举到的元素进入堆内
第一个 push 的意义是下次如果其作为堆顶元素、那么可以把它拿出来做减法达到反悔操作
第二个 push 的意义是下次拿出来的话就是真正的卖出去
代码:
#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 10;
int n;
int a[maxn];
priority_queue<int, vector<int>, greater<int> > Q;
map<int, int> mp;
int main()
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
while(!Q.empty()) Q.pop(); mp.clear();
long long ans = 0, cnt = 0;
for(int i = 0; i < n; i++){
if(!Q.empty() && Q.top() < a[i]){
int x = Q.top(); Q.pop();
ans += a[i] - x; cnt++;
if(mp[x]){ mp[x]--; cnt--;}
Q.push(a[i]); mp[a[i]]++;
}
Q.push(a[i]);
}
printf("%lld %lld\n", ans, cnt << 1);
}
return 0;
}