【队内胡策 10.24 T3】洛圣都

来源:互联网 发布:.cn域名的ns记录 查询 编辑:程序博客网 时间:2024/05/19 17:48

题目来源:Codeforce867E(865D) Buy Low Sell High
去题面的传送门
这里写图片描述

第一反应是一个之前做过的DP,条件稍微改了一下,但是打了半天发现不对。好吧最后还是没有打出水分的DP
正解是贪心
很神奇的做法
首先来说一下做法,维护一个小根堆,从第一天到第n天for一遍,如果这一天的价格小于堆顶元素,直接加入堆。如果大于,ans+=该天的价格与堆顶元素的差,在堆里放入两个该天的价格,直到第n天。
为什么这样是正确的呢?
首先对于一个小于或等于堆顶元素的值,肯定是买入,也就是放入堆,这一点毋庸置疑
对于一个大于堆顶元素的值:设堆顶元素为a,当前价格为b,即a < b,如果后面没有比b大的数了,这时b-a一定是最优的。如果后面有一个数c > b,即存在a < b < c,如果遇到了c,那么ans+=c-b,一加一减,b就消掉了。也就是说,如果存在比b更优的c,我们可以通过这种方式来使答案变成更优的c-a。至于为什么要push两个b?第一个是为了后来遇到c时,能够pop出b,第二个是为了,如果遇到了c,把b给pop掉了,但是b有可能和后面的另一个比b大的数d对答案贡献d-b,这时候第二个就用上了。因为每次都是取出之前已经遍历到过的最小值,所以答案一定是最优的。
最后堆里还会剩下一些元素,显然,这些元素都是比前面已经pop掉的元素大的,如果使用它们,肯定不会使答案更优,所以最后他们就是卖不出去的那些股票,也就是我们选择什么都不做的那一天的股票。

—————————————-萌萌的分割线—————————————-

看dalao的题解

题目条件:
① : 可以在接下来的 N 天内完全预测某种股票的价格;
② :每天只能处理一份股票,要么买一份, 要么卖一份,要么什么也不做;
贪心。
每天给出一个股票价格,可以选择在这一天以这一价格买入或卖出。 对于第三个条件不需要考虑,只需根据后面的处理过程假设在这一天 买入或卖出,
并不需要“持有”任何股票。 显然,为了赚到更多的钱,需要在价格较低时买入,价格较高时卖出。 但是并不知道具体在哪一天是买入或卖出的最好时间。
于是维护一个小根堆。 由于卖出的只能是先前已经买入的,所以小根堆中记录当天 之前的信息。之后每加入一天的价格,将当前价格与堆顶(最小元素)
比较: now>top, 将 now-top 加入答案; now < =top, 将 now 放入堆。 然而这样的策略并不完美。 例如: 3,4,7 。按照以上思路, 遍历到 4 时发现 4 比 3 大就直接把 4-3 加入了答案, 实际上存在更优解: 7-3=4
观察发现
7-3=(4-3)+(7-4), 也就相当于没有用到 4 。也就是说,如果只考虑 a < b < c 这样的子序列, b 是用不到的, 但是在 遍历到c 之前,无法确定是否会出现这样的情况。 一旦出现这样的情 况, b 对答案无影响并且 b 可能在以后用到。 这时候考虑放进去两个 b。
具体思路: ① 遍历到 a,放 a;
③ 如果之后找到一个 c>b, b 作为堆顶元素被买, 将 c-b 加入答案。此 时加入的答案总和为:(b-a)+(c-b) =c-a , b 用不到,但是 b 被 减没了, 如果后面有 f>b, 这时放入的另一个 b 就派上了用场;
④ 将 b 放进去后,如果 b 从此以后一直是比较大的,那么之后一定不会再以 b 价格买入, b 不会成为堆顶, 放进去的另一个 b 就一直 用不到。
这样, 就对每一个可以进行操作堆顶元素执行了买的操作, 对每一个 当前遍历到的比堆顶元素大的元素执行了卖的操作。最后可能会剩下
一些卖不出去的东西, 这就相当于在股票价格为剩下的元素时,不执 行任何操作,以上是对整个序列进行判断比较后得到最优解的过程。
因此不需要考虑当前“持有”的股票数量以及如何使最后剩余的股票 数为 0 的策略。

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<queue>using namespace std;const int maxn=300000+10;long long n,ans;long long p[maxn];struct hh{    long long x;};priority_queue<hh>q;bool operator < (hh x,hh y){    return x.x>y.x;}int main(){    scanf("%d",&n);    for(long long i=1;i<=n;++i) scanf("%d",&p[i]);    for(long long i=1;i<=n;++i)    {        if(q.empty()) q.push((hh){p[i]});        else if(q.top().x<=p[i])        {            ans+=p[i]-q.top().x;            q.pop();            q.push((hh){p[i]});            q.push((hh){p[i]});        }        else q.push((hh){p[i]});    }    printf("%lld",ans);    return 0;}
原创粉丝点击