NOI2007 货币兑换

【问题描述】

  小 Y最近在一家金券交易所工作。该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券)。每个持有金券的顾客都有一个自己的 帐户。金券的数目可以是一个实数。每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目。我们记录第K天中A券 和B券的价值分别为AK和BK(元/单位金券)。
为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法。
比例交易法分为两个方面:
a)卖出金券:顾客提供一个[0,100]内的实数OP作为卖出比例,其意义为:将OP%的A券和OP%的B券以当时的价值兑换为人民币;
b)买入金券:顾客支付IP元人民币,交易所将会兑换给用户总价值为IP的金券,并且,满足提供给顾客的A券和B券的比例在第K天恰好为RateK;
例如,假定接下来3天内的Ak、Bk、RateK的变化分别为:

时间 Ak Bk Ratek
第一天 1 1 1
第二天 1 2 2
第三天 2 2 3

假定在第一天时,用户手中有100元人民币但是没有任何金券。
用户可以执行以下的操作:

时间 用户操作 人民币(元) A券的数量 B券的数量
开户 100 0 0
第一天 买入100元 0 50 50
第二天 卖出50% 75 25 25
第二天 买入60元 15 55 40
第三天 卖出100% 205 0 0

注意到,同一天内可以进行多次操作。
小Y是一个很有经济头脑的员工,通过较长时间的运作和行情测算,他已经知道了未来N天内的A券和B券的价值以及Rate。他还希望能够计算出来,如果开始时拥有S元钱,那么N天后最多能够获得多少元钱。

【输入格式】

第一行两个正整数N、S,分别表示小Y能预知的天数以及初始时拥有的钱数。接下来N行,第K行三个实数AK、BK、RateK,意义如题目中所述。

【输出格式】

只有一个实数MaxProfit,表示第N天的操作结束时能够获得的最大的金钱数目。答案保留3位小数。

-----------------------------------------------------------

正解=动归+平衡树

考虑简单Dp

   状态:设f[i]为第i天能赚的最多钱为多少

   方程:f[i]=max(f[i-1],na*A+nb*B)(j< i)

    (na,nb为第j天能换到的A劵数量和B劵数量)

考虑优化:

  设 na 为 x,nb 为 y

  则sum=x*A+y*B 既 y = -A/B*x+sum/B

  由于A,B为定值

   sum的Max以 -A/B 为斜率的过点(x,y)的截距的Max*B

  显然可能得到Max解截距的点必然是个上凸壳

    建立以x为关键字的平衡树维护值(其实很简(dan)单(teng))

      由于在树上的点映射的截距具有单调性,

  找最大值是便可通过平衡树的前驱后继判断Max在左子树或右子树;

代码如下:

  

  1 #include<cstring>

  2 #include<algorithm>

  3 #include<cstdio>

  4 #include<string>

  5 #include<iostream>

  6 #include<queue>

  7 #define INF 99999999

  8 #define LL long long

  9 #define Cint(o) const int o=0

 10 #define Cdou(o) const double o=0

 11 #define Min(num1,num2) if(num1>num2) num1=num2

 12 #define Max(num1,num2) if(num1<num2) num1=num2

 13 struct Tree{

 14     int l,r,f;

 15     double x,y;

 16     Tree(Cint(a1),Cint(a2),Cint(a3),Cdou(a4),Cdou(a5)):

 17         l(a1),r(a2),f(a3),x(a4),y(a5){}

 18 }a[100010];

 19 int Root,Total,n;

 20 const long double O=1e-8;

 21 void cal(double sum,double A,double B,double K,double &na,double &nb){

 22     nb=sum/(A*K+B);

 23     na=nb*K;

 24 }

 25 void rig(int now){

 26     int f=a[now].f;

 27     a[now].f=a[f].f;

 28     if(a[a[f].f].l==f) a[a[f].f].l=now;

 29     if(a[a[f].f].r==f) a[a[f].f].r=now;

 30     a[f].f=now;

 31     a[f].l=a[now].r;

 32     a[a[now].r].f=f;

 33     a[now].r=f;

 34 }

 35     

 36 void lef(int now){

 37     int f=a[now].f;

 38     a[now].f=a[f].f;

 39     if(a[a[f].f].l==f) a[a[f].f].l=now;

 40     if(a[a[f].f].r==f) a[a[f].f].r=now;

 41     a[f].f=now;

 42     a[f].r=a[now].l;

 43     a[a[now].l].f=f;

 44     a[now].l=f;

 45 }

 46 double cross(Tree A,Tree B,Tree C){

 47     return (B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y-A.y);

 48             // x1 *y2-x2*y1

 49 }    

 50 void splay(int now,int F=0){

 51     while(a[now].f!=F){

 52         int f=a[now].f,ff=a[f].f;

 53         if(ff==F)

 54             if(a[f].l==now) rig(now);

 55             else lef(now);

 56         else

 57             if(a[ff].l==f)

 58                 if(a[f].l==now) rig(f),rig(now);

 59                 else lef(now),rig(now);

 60             else

 61                 if(a[f].l==now) rig(now),lef(now);

 62                 else lef(f),lef(now);

 63     }

 64     if(!F) Root=now;

 65 }

 66 

 67 void creat(){

 68     Total=2;

 69     Root=1;

 70     a[1].r=2;

 71     a[2].f=1;

 72     a[1].x=-INF;

 73     a[2].x=INF;

 74 }

 75 int prev(int now){

 76     splay(now);

 77     now=a[now].l;

 78     while(a[now].r) now=a[now].r;

 79     return now;

 80 }

 81 int succ(int now){

 82     splay(now);

 83     now=a[now].r;

 84     while(a[now].l) now=a[now].l;

 85     return now;

 86 }

 87 void del(int start,int now,int end){

 88     splay(start);

 89     splay(end,start);

 90     a[a[Root].r].l=0;

 91     //printf("Delte(%d)",now);

 92 }

 93 void maintain(int now){

 94     int p=prev(now),s=succ(now);

 95     if(p!=1&&s!=2)

 96         if(cross(a[p],a[s],a[now])<O){

 97             del(p,now,s);

 98             return ;

 99         }

100     while(1){

101         if(p==1) break;

102         int pp=prev(p);

103         if(pp!=1&&cross(a[pp],a[now],a[p])<O)

104             del(pp,p,now),

105             p=pp;

106         else 

107             break;

108     }

109     while(1){

110         if(s==2) break;

111         int ss=succ(s);

112         if(ss!=2&&cross(a[now],a[ss],a[s])<O)

113             del(now,s,ss),

114             s=ss;

115         else 

116             break;

117     }

118 }

119 void insert(double x,double y){

120     for(int now=Root;;){

121         if(a[now].x-x<O&&x-a[now].x<O){

122             Max(a[now].y,y);

123             maintain(now);

124             return ;

125         }

126         if(a[now].x-x>O)

127             if(a[now].l)

128                 now=a[now].l;

129             else {

130                 a[now].l=++Total;

131                 a[Total].f=now;

132                 a[Total].x=x;

133                 a[Total].y=y;

134                 maintain(Total);

135                 return ;

136             }

137         else 

138             if(a[now].r)

139                 now=a[now].r;

140             else{

141                 a[now].r=++Total;

142                 a[Total].f=now;

143                 a[Total].x=x;

144                 a[Total].y=y;

145                 maintain(Total);

146                 return ;    

147                 

148             }    

149     }

150 }

151 double fo(Tree now,double K){

152     return now.y-now.x*K;

153 }

154 int pre(int now){

155     //splay(now);

156     now=a[now].l;

157     while(a[now].r) now=a[now].r;

158     return now;

159 }

160 

161 int suc(int now){

162 //    splay(now);

163     now=a[now].r;

164     while(a[now].l) now=a[now].l;

165     return now;

166 }

167 double slove(double K){

168     for(int now=Root;;){

169         if(now==1){

170             now=suc(now);

171             continue ;

172         }

173         if(now==2){

174             now=pre(now);

175             continue ;

176         }

177         

178         if(a[now].l){

179             int k=pre(now);

180             if(k!=1&&fo(a[now],K)<fo(a[k],K)+O){

181                 now=a[now].l;

182                 continue ;

183             }

184         } 

185         if(a[now].r){

186             int k=suc(now);

187             if(k!=2&&fo(a[now],K)<fo(a[k],K)+O){

188                 now=a[now].r;

189                 continue ;

190             }

191         }

192         return fo(a[now],K);

193         

194     }

195 } 

196 int main(){

197     double A,B,K,na,nb,s;

198     scanf("%d%lf",&n,&s);

199     scanf("%lf%lf%lf",&A,&B,&K);

200     creat();

201     cal(s,A,B,K,na,nb);

202     insert(na,nb);

203     for(int i=1;i<n;i++){

204         scanf("%lf%lf%lf",&A,&B,&K);

205         double temp=slove(-A/B)*B;

206         Max(s,temp);

207         cal(s,A,B,K,na,nb);

208         insert(na,nb);

209     }

210     printf("%.3lf",s);

211 }
View Code

 

你可能感兴趣的:(2007)