题面
已知接下来(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)
代码
自己写