【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\n",cnt,ans);
64 }
65 int main()
66 {
67     while(~scanf("%d",&n)){
68         work();
69         num=0;
70     }
71 }

 

posted @ 2017-05-21 21:39  PIPIBoss  阅读(1151)  评论(0编辑  收藏  举报