CF865D Buy Low Sell High——反悔贪心堆

做题链接

题面

已知接下来\(N\)天的股票价格,每天你可以买进一股股票,卖出一股股票,或者什么也不做.\(N\)天之后你拥有的股

票应为\(0\),当然,希望这N天内能够赚足够多的钱.

输入:

第一行一个整数天数\(N\)(\(2<=N<=300000\)).

第二行N个数字\(p_1,p_2...p_N\)(\(1<=pi<=10^6\)),表示每天的价格.

输出: \(N\)天结束后能获得的最大利润.

思路

我们可以快速想出一种贪心策略:买入价格最小的股票,在可以赚钱的当天卖出。

显然我们可以发现,上面的贪心策略是错误的,因为我们买入的股票可以等到可以赚最多的当天在卖

出。我们考虑设计一种反悔策略,使所有的贪心情况都可以得到全局最优解。(即设计反悔自动机的反

悔策略)定义\(C_{buy}\)为全局最优解中买入当天的价格, \(C_{sell}\) 为全局最优解中卖出当天的价格,则:

\(C_{sell}-C_{buy}=(C_{sell}-C_{i})+(C_{i}-C_{buy})\)

\(C_i\)为任意一天的股票价格

考虑怎么反悔

我们将每天的价格视为一个个"选项", 压入小根堆中,为了保证买入操作在卖出操作之前,我们从前往

后扫描\(p\),对于现在的价格 \(p_i\),如果堆顶元素\(p_j\) 满足 \(p_{j}<p_i\) ,那么,我们取出

堆顶,在第\(j\)天买入股票,在第\(i\)天卖出股票,此时,我们就可以获得\(p_i - p_j\) 的收益

然而,如果之后有\(p_k\)满足\(p_k > p_i\),辣么,我们当前作出的决策可能并不是最优的,

如何反悔呢?

于是,当我们进行上述操作时,我们将\(p_i\)也压入堆中,增加一个\(p_i\)的选项,弹出时,我们相当

于将\(p_j\)按照\(p_i\)的价格又买了回来

就比如我们 \(4 \ 5 \ 6\)这个序列,按照程序我们应该是先买入\(4\),然后卖出\(5\)\(ans+=1\),但是显然后面

在6的时候卖会更优,所以我们为了给电脑留出余地,我们再多保存一个历史的状态,再往队列中压入一

个5,这个时候我们还会在6的时候,卖出,并且\(ans+=1\),正确

其实就相当于是\(ans=(6-5)+(5-4)=6-4\)

代码

自己写

posted @ 2020-11-10 14:16  邦的轩辕  阅读(54)  评论(0)    收藏  举报