【CF865D】Buy Low Sell High(贪心)
题面
题解
首先有一个\(O(n^2)\)的\(dp\)很显然,设\(f[i][j]\)表示前\(i\)天手中还有\(j\)股股票的最大收益。转移显然。
然而这样子似乎并没有什么优化的余地。
考虑这样子一个贪心,假设我们已经知道了前面\(n-1\)天在最优答案的情况下的购买和卖出情况,只考虑最后这一天,那么你会找到一个可以买入股票的一天,并且其价格最小,然后和这一天的股票价格进行比较,如果更低,你就会在那一天买入股票,在这一天卖掉。
但是如果从头到尾每天都这样子进行贪心,那么显然是假的。
那么我们这么处理,维护一个堆表示之前的所有可行的决策,如果当前天的价格还要小于堆中的最小值,显然我们不会购买,直接把这个价格丢进堆里,否则会在堆顶那天买入,在这一天卖出,假设堆顶那一天的价格是\(x\),当天的价格是\(y\),那么就会得到\(y-x\)的收益。但是后面某天的决策可能是在那一天卖出,在第\(x\)天买入,所以往堆里面再插入一个\(x-(y-x)\),那么如果你在后面的某天购买到了这个\(x-(y-x)\),即表示你把当前这一天的卖出操作替换成了在后面那一天卖出,然后再在堆内插入一个\(y\),因为前面插入的元素一定会在这个\(y\)之前被弹出堆,因此只可能在这一天不卖之后才会用到这个\(y\),表示在这一天买入。
那么这样子贪心就好了。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#define ll long long
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
ll ans;int n;
priority_queue<int> Q;
int main()
{
n=read();Q.push(-read());
for(int i=2;i<=n;++i)
{
int y=read();
if(y<=-Q.top())Q.push(-y);
else ans+=y+Q.top(),Q.pop(),Q.push(-y),Q.push(-y);
}
printf("%I64d\n",ans);
return 0;
}