CF865D Buy Low Sell High

发布时间 2023-07-11 19:40:21作者: 霜木_Atomic

CF865D Buy Low Sell High

我发现自己是真的学不会贪心……太玄学了。
这是一道反悔贪心的题目,比较简单的那种。

题意

你是一棵韭菜,喜欢炒股,每天可以买入一股或卖出一股,且最后一天之后你持有的股票数目应该为 \(0\)。你现在知道 \(n\) 天的股票价格,求最大获利。

思路

首先一个很显然的策略就是,我们从前往后扫,对于每一个数,找到它之前最小的那个数,如果可以获利,就增加答案。但这样有一个显然的问题,就是如果之后有价格更高的天数,那之前的最小价格就“浪费”了,我们现在就是要对这个浪费进行一个反悔。
我们发现,在第 \(i\) 天买入股票,在第 \(j\) 天卖出,等价于你在第 \(i\) 天买入,在第 \(k\) $(i < k < j) $天卖出后立刻买入,然后在第 \(j\) 天卖出。在这个过程中,你的第 \(k\) 天实际上是没有买卖的,但是你的实际操作是进行了买卖。那我们可以利用堆来维护前 \(i-1\) 天的最小价格,每次把第 \(i\) 个价格插入堆,如果可以买卖,就再次插入第 \(i\) 个价格。这时候,第二个插入的价格就相当于上文中的第 \(k\) 个价格,用来让以后的可能有的更大的数去贡献答案,也就是说,对于每一个可能贡献答案的价格,都要减两次才能真正成为那个买入的价格。
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5+10;

inline int read(){
	int x = 0; char ch = getchar();
	while(ch<'0' || ch>'9') ch = getchar();
	while(ch>='0' && ch<='9') x = x*10+ch-48, ch = getchar();
	return x;
}
int n;
ll ans;
priority_queue<int, vector<int>, greater<int> > q;
int main(){
	n = read();
	for(int i = 1; i<=n; ++i){
		int tmp = read();q.push(tmp);
		if(q.size() && tmp>q.top()) ans+=tmp-q.top(), q.pop(), q.push(tmp);
		
	}
	printf("%lld\n", ans);
	return 0;
}