• 【LSGDOJ1836】: 量化交易 贪心


    题目描述

    applepi 训练了一个可以自动在股票市场进行量化交易的模型。通常来说,applepi 写出的模型,你懂得,就好比一架印钞机。不过为了谨慎起见,applepi还是想先检查一下模型的效果。applpie 收集了“塞帕思股份(surpass)”在最近的连续 N 天内的价格。在每一天中,他可以做如下事情之一:
    1. 睡(把)觉(妹)。
    2. 以当天的价格作为成交价买入 1 股“塞帕思”的股票。
    3. 以当天的价格作为成交价卖出 1 股“塞帕思”的股票。
    最初 applepi 不持有该股票。现在你需要计算出在最优策略下,N 天后 applepi能够获得的最大利润。为了维护森林的和平,本着清仓甩锅的原则,在 N 天的交易结束后 applepi 也不能持有“塞帕思”的股票。

    输入

    每个测试点包含若干组数据。对于每组数据:
    第一行 1 个整数 N。
    第二行 N 个正整数,相邻两个整数之间用 1 个空格隔开,表示每一天股票的价格。

    输出

    对于每组数据,首先按样例所示的格式“Case #k:”输出该组数据的编号,然后输出一个整数,表示 applepi 最大能够获得的利润。

    样例输入

    6 2 6 7 3 5 6 8 1 2 3 4 5 6 7 8

    样例输出

    Case #1: 8
    Case #2: 16

    提示

    样例输入 2  

    10
    15831 47573 60015 51368 32460 34125 43074 75172 54014 93578

    样例输出 2

    Case #1: 161084
     

    对于 50%的数据,1≤N≤1000。

    对于 100%的数据,1≤N≤100000,股票价格不超过 100000,每个测试点至多包含 5 组数据。
     
    题解:
    这题正解好巧妙:
    是个人都知道:如果当前已经买了一股,那么就要卖到最大的一天.
    ->但是我们并不知道那一天最大.
    ->于是我们在能产生利润时就卖掉.
    ->但是我们需要一个“后悔”操作,表示那天不卖,在此时利润更大时再买.
     
    于是开个小根堆表示已经买了的股票.
    当输入小于堆顶说明产生不了利益,先买掉
    当输入大于堆顶说明可以产生利润,于是卖掉,并且把当天股价加入堆中两次(可以达到“后悔”的效果)
     
    下面是”后悔“操作的原理:
    假设堆顶是第a天的报价,当前是第b的的报价,第a天买进的股票应该在第c天卖出,
    第b天买进的股票需要在第d天卖出,
    a<b<c<d,收益p[c]-p[a]+p[d]-p[b]
    现在把第a天的股票在第b天抛出,p[b]-p[a],然后又买进第b天的股票,那么在第c天的时候,
    堆顶为第b天的股票,抛出第b天的股票 p[c]-p[b],收益总和p[b]-p[a]+p[c]-p[b]=p[c]-p[a]
    但因为第b天的股票应该在第d天抛出,所以要第二次再次买进第b天的股票
     
    下面来分析具体含义:
    1.假如一个元素被取出一次,说明当天既没买也没卖(睡觉)
    2.假如取出了两次,说明确实是卖掉了.
    3.加入一个元素没有被取出过,相当于在当天买了.
     
    为什么答案满足最大:
    1.买入的都是没有被取出过的,因为是小根堆,所以满足最大.
    2.同理卖出的都是最小的.
    3.又因为是按i=1-n处理的所以满足买卖顺序.
    下面是代码:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 #include<vector>
     8 using namespace std;
     9 int n;
    10 int gi(){
    11     int str=0;char ch=getchar();
    12     while(ch>'9' || ch<'0')ch=getchar();
    13     while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar();
    14     return str;
    15 }
    16 int cnt=0;
    17 int t[400000],num=0;
    18 void putin(int x)
    19 {
    20     t[++num]=x;
    21     int now=num,next;
    22     while(now>1)
    23     {
    24         next=(now>>1);
    25         if(t[now]>=t[next])break;
    26         swap(t[now],t[next]);
    27         now=next;
    28     }
    29 }
    30  
    31 int getit()
    32 {
    33     int str=t[1];
    34     t[1]=t[num--];
    35     int now=1,next;
    36     while((now<<1)<=num)
    37     {
    38         next=now<<1;
    39         if(t[next]>t[next+1] && next<num)next++;
    40         if(t[now]<=t[next])break;
    41         swap(t[now],t[next]);
    42         now=next;
    43     }
    44     return str;
    45 }
    46  
    47 void work()
    48 {
    49     cnt++;
    50     int x,tmp;long long ans=0;
    51     for(int i=1;i<=n;i++)
    52     {
    53         x=gi();
    54         if(!num || t[1]>=x)putin(x);
    55         else
    56         {
    57             tmp=getit();
    58             ans+=x-tmp;
    59             putin(x);
    60             putin(x);
    61         }
    62     }
    63     printf("Case #%d: %lld
    ",cnt,ans);
    64 }
    65 int main()
    66 {
    67     while(~scanf("%d",&n)){
    68         work();
    69         num=0;
    70     }
    71 }
  • 相关阅读:
    iOS企业证书开发的APP证书过期时间监控
    事件冒泡,事件捕获
    倒计时
    获取多个div,点击第几个,显示第几个
    js继承
    javascript基础知识总结
    大型web系统高效应用方法(转载)
    数据库(内联,外联,交叉联)
    .net零碎基础知识点不完全小结
    C#的内存管理:堆、栈、托管堆与指针(转)
  • 原文地址:https://www.cnblogs.com/Yuzao/p/6886194.html
Copyright © 2020-2023  润新知