一眼就可以看出是贪心,问题就是怎么去操作
首先一个很显然的思路就是,开一个小根堆,每次对于一个价格x,如果低于堆顶我们就将其丢进去,否则将堆顶y取出,获得x-y的贡献
但是这样是有问题的,我们会发现有反例: 1 4 2 3 用这种方法求出的答案是1但是正确答案应该是2
所以我们需要增加一种“撤销操作”
类似于种花那道题,我们每次将答案加上了x-y时候,我们也将x丢入堆中,而且要丢入两次,为什么?
举个例子:1 2 3 4
我们在做到2的时候,我们将第一天的股票卖了得到1的收益,但是实际上,2这一天不应该卖反而应该买,所以原本在第2天的交易量由-1变为了1,变化量为2
也就是说,对于一个对答案做出贡献的x,我们将其丢入堆中*2,则第一次取出,相当于撤回一次出售,比如对于第三天的3(收益为3-(2-1)=2)
第二次取出,则相当于将其也作为买入的一天,比如第四天(4-2=2)
所以总收入为2+2=4
这题卡常,建议手打堆(我过了是因为jz跑得快)
#include<stdio.h>
#include<queue>
using namespace std;
int main(){
freopen("trade.in","r",stdin);
freopen("trade.out","w",stdout);
for(int n,T=1;~scanf("%d",&n);++T){
unsigned ans=0;
priority_queue<int,vector<int>,greater<int> > q;
for(int x,i=0;i<n;++i){
scanf("%d",&x);
if(q.empty()||x<=q.top()) q.push(x);
else {
ans+=x-q.top(); q.pop();
q.push(x); q.push(x);
}
}
printf("Case #%d: %u
",T,ans);
}
}