CF865D Buy Low Sell High

题意翻译

已知接下来N天的股票价格,天天你能够买进一股股票,卖出一股股票,或者什么也不作.N天以后你拥有的股票应为0,固然,但愿这N天内可以赚足够多的钱.
输入:
第一行一个整数天数N(2<=N<=300000).
第二行N个数字p1,p2...pN(1<=pi<=10^6),表示天天的价格.
输出: N天结束后能得到的最大利润.c++

题解

很是经典的贪心问题spa

 

用一个优先队列小根堆。翻译

假设每一个股票都买入。code

当前的股票价格>堆顶的时候,把这个股票加进去两次。而后弹出堆顶。blog

不然加进去一次。队列

把这个差价计入ans,ans+=price[i]-q.top()it

 

什么意义呢?io

首先,咱们虽然假设都买入,可是并不必定都买。class

咱们只有在计算差价的时候,至关于才会把某个价格买入,再以price[i]卖出。queue

而咱们把这个股票加进去两次,

一次是正常的假设买入。为了以后可能赚取差价。

另外一次是为了反悔。

假设股票价格是:3 7 10

最优解是3买入,10卖出,赚7元

也就是说,我以3价格买入,但我会在7元的时候卖出。

可是7元卖可能不是最优秀的。

因此,咱们把7元再加进去,当轮到10元的时候,这个7元会再当作一个股票卖出ans+=10-7

发现,有意思的是,10-3=(10-7)+(7-3)

这就至关于3元买入,10元卖出。7元这天摸鱼。

若是10后面假设还有一个20

即3,7,10,20

那么,咱们10元以后,队列里有7,10,10

20元会7元买入,20元卖出。至关于7元这天买入了一股。

 

这样下去,咱们总能把最少的价格买入,尽可能多的价格卖出。

若是不是最优秀的话,就不买不卖了。就是最后优先队列里剩下的一些。就是预约买入,可是实际没有买入的部分。

 

#include<bits/stdc++.h>
using namespace std;
const int N=300000+10;
int n;
int p[N];
priority_queue<int,vector<int>,greater<int> >q;
long long ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&p[i]);
        q.push(p[i]);
        if(!q.empty()&&q.top()<p[i]){
            ans+=p[i]-q.top();
            q.pop();
            q.push(p[i]);
        }
        
    }printf("%lld",ans);return 0;
}

总结:

反悔堆的比较厉害的应用了。

利用差价的关系,直接处理。

怎么想到的?
首先要想到贪心,而后这个题确定要用一个反悔堆之类。

那么,咱们假设先买入,仍是先都不买?

都不买太被动。

那就都买入,而后结算的时候,再真实买入。

可是对于不是最优的抛售天怎么办?

利用差价。便可。

相关文章
相关标签/搜索