【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
第一天   买入 1000                  50               50
第二天    卖出 50%             75                25               25
第二天    买入 6015                55               40
第三天    卖出 100%           205               0                0
注意到,同一天内可以进行多次操作。
小 Y 是一个很有经济头脑的员工,通过较长时间的运作和行情测算,他已经
知道了未来 N 天内的 A 券和 B 券的价值以及 Rate。他还希望能够计算出来,如
果开始时拥有 S 元钱,那么 N 天后最多能够获得多少元钱。
输入文件
第一行两个正整数 N、 分别表示小 Y 能预知的天数以及初始时拥有的钱数。
接下来 N 行,第 K 行三个实数 AK、BK、RateK,意义如题目中所述。
输出文件
只有一个实数 MaxProfit,表示第 N 天的操作结束时能够获得的最大的金钱
数目。答案保留 3 位小数。
输入样例
3
1
1
2
100
1 1
2 2
2 3
输出样例
225.000
样例说明
时间             用户操作                         人民币(元)          A 券的数量         B 券的数量
开户                 无                                      100                     0                        0
第一天          买入 1000                       50                       50         
第二天          卖出 100%                          150                      0                         0
第二天          买入 1500                       75                      37.5       
第三天          卖出 100%                        225                        0                          0           

评分方法
本题没有部分分,你的程序的输出只有和标准答案相差不超过0.001时,才能
获得该测试点的满分,否则不得分。
数据规模和约定
测试数据设计使得精度误差不会超过 10-7。
对于 40%的测试数据,满足 N ≤ 10;
对于 60%的测试数据,满足 N ≤ 1 000;
对于 100%的测试数据,满足 N ≤ 100 000;
对于 100%的测试数据,满足:
0 < AK ≤ 10;
0 < BK ≤ 10;
0 < RateK ≤ 100
MaxProfit ≤ 109;
提示
输入文件可能很大,请采用快速的读入方式。
必然存在一种最优的买卖方案满足:
每次买进操作使用完所有的人民币;
每次卖出操作卖出所有的金券。

 

题解

 

解法1:搜索
 1 (*
 2     Problem:    NOI2007 货币兑换
 3     Author:        Chen Yang
 4     Time:        2012.5.24 9:00 am
 5     state:        40分
 6     Memo:        搜索
 7 *)
 8 program cash;
 9 const zero=1e-8;
10 var
11   n,i:longint;
12   s,ans:extended;
13   a,b,rate:array[0..100000] of extended;
14   maxv,maxa,maxb:array[0..100000] of extended;
15 //=================
16 procedure find(x:longint; v,sa,sb:extended);
17 var
18   tot:extended;
19 begin
20   if x=n then
21   begin
22     v:=v+sa*a[n]+sb*b[n];
23     if v>ans then ans:=v;
24     exit;
25   end;
26   if (v>zero)and(v<maxv[x]-zero) then exit;
27   if v>maxv[x] then maxv[x]:=v;
28   if (sa>zero)and(sa<maxa[x]-zero)and(sb<maxb[x]-zero) then exit;
29   if (sa>maxa[x])and(sb>maxb[x]) then
30   begin
31     maxa[x]:=sa; maxb[x]:=sb;
32   end;
33   find(x+1,v,sa,sb);
34   if v>zero then
35   begin
36     tot:=v/(rate[x]*a[x]+b[x]);
37     find(x+1,0,sa+rate[x]*tot,sb+tot);
38   end;
39   if sa>zero then
40   begin
41     v:=v+sa*a[x]+sb*b[x];
42     find(x+1,v,0,0);
43     tot:=v/(rate[x]*a[x]+b[x]);
44     find(x+1,0,rate[x]*tot,tot);
45   end;
46 end;
47 //=================
48 begin
49   assign(input,'cash.in'); reset(input);
50   assign(output,'cash.out'); rewrite(output);
51   read(n,s);
52   for i:=1 to n do read(a[i],b[i],rate[i]);
53   find(1,s,0,0);
54   writeln(ans:0:3);
55   close(input); close(output);
56 end.

 

解法2:朴素DP
 1 (*
 2     Problem:    NOI2007 货币兑换
 3     Author:        Chen Yang
 4     Time:        2012.5.24 8:00 pm
 5     State:        60分
 6     Memo:        朴素DP
 7 *)
 8 program cash;
 9 uses math;
10 const maxn=100100;
11 var
12   n,i,j:longint;
13   old:extended;
14   g:array[0..maxn] of longint;
15   f,fa,fb,a,b,rate:array[0..maxn] of extended;
16 //===================
17 begin
18   assign(input,'cash.in'); reset(input);
19   assign(output,'cash.out'); rewrite(output);
20   read(n,f[0]);
21   for i:=1 to n do read(a[i],b[i],rate[i]);
22   for i:=1 to n do
23   begin
24     f[i]:=f[i-1];
25     for j:=1 to i-1 do
26     begin
27       old:=f[i];
28       f[i]:=max(f[i],fa[j]*a[i]+fb[j]*b[i]);
29       if f[i]>old then g[i]:=j;
30     end;
31     writeln(g[i]);
32     fb[i]:=f[i]/(rate[i]*a[i]+b[i]);
33     fa[i]:=fb[i]*rate[i];
34   end;
35   //writeln(g[143]);
36   //for i:=1 to n do writeln(f[i]:0:3);
37   writeln(f[n]:0:3);
38   close(input); close(output);
39 end.

 

解法3:用平衡树优化DP(treap)
  1 (*
  2     problem:    NOI2007 货币兑换
  3     Author:        Chen Yang
  4     Time:        2012.5.25 4:20 pm
  5     State:        AC
  6     Memo:        斜率、treap优化DP
  7 *)
  8 program cash;
  9 const maxn=100100;
 10       maxs=400400;
 11       zero=1e-8;
 12 var
 13   n,m,i,j,root,pp,ss:longint;
 14   s,l,r,rand:array[0..maxs] of longint;
 15   f,x,y,a,b,rate:array[0..maxn] of double;
 16 //===================
 17 function max(a,b:double):double;         inline;
 18 begin if a>b then exit(a) else exit(b); end;
 19 //===================
 20 procedure l_rotate(var k:longint);       inline;
 21 var y:longint;
 22 begin
 23   y:=r[k]; r[k]:=l[y]; l[y]:=k; k:=y;
 24 end;
 25 //===================
 26 procedure r_rotate(var k:longint);       inline;
 27 var y:longint;
 28 begin
 29   y:=l[k]; l[k]:=r[y]; r[y]:=k; k:=y;
 30 end;
 31 //===================
 32 function c_k(i,j:longint):double;        inline;
 33 begin exit((y[j]-y[i])/(x[j]-x[i])); end;
 34 //===================
 35 function pre(k,t:longint):longint;
 36 var i:longint;
 37 begin
 38   if k=0 then exit(0);
 39   if (x[s[k]]<x[t]-zero)or(s[k]<>t)and(abs(x[s[k]]-x[t])<zero) then
 40   begin
 41     i:=pre(r[k],t);
 42     if (i=0)and(s[k]<>t) then exit(s[k]) else exit(i);
 43   end else exit(pre(l[k],t));
 44 end;
 45 //===================
 46 function suc(k,t:longint):longint;
 47 var i:longint;
 48 begin
 49   if k=0 then exit(0);
 50   if (x[s[k]]>x[t]+zero)or(s[k]<>t)and(abs(x[s[k]]-x[t])<zero) then
 51   begin
 52     i:=suc(l[k],t);
 53     if (i=0)and(s[k]<>t) then exit(s[k]) else exit(i);
 54   end else exit(suc(r[k],t));
 55 end;
 56 //===================
 57 function delete(var k:longint; t:longint):longint;
 58 begin
 59   if (abs(x[t]-x[s[k]])<zero) or
 60      (x[t]<x[s[k]]-zero) and (l[k]=0) or
 61      (x[t]>x[s[k]]+zero) and (r[k]=0) then
 62   begin
 63     delete:=s[k];
 64     if (l[k]=0)or(r[k]=0) then
 65     begin
 66       k:=l[k]+r[k];
 67       exit;
 68     end;
 69     s[k]:=delete(l[k],t);
 70     exit;
 71   end;
 72   if x[t]<x[s[k]]+zero then exit(delete(l[k],t)) else exit(delete(r[k],t));
 73 end;
 74 //===================
 75 function check(i:longint; var p,s:longint):boolean;       inline;
 76 begin
 77   p:=pre(root,i); s:=suc(root,i);
 78   if (p=0)or(s=0) then exit(true);
 79   if abs(x[p]-x[i])<zero then
 80   begin
 81     if y[p]>y[i]-zero then exit(false) else
 82     begin delete(root,p); exit(true); end;
 83   end;
 84   exit(c_k(p,i)>c_k(i,s)+zero);
 85 end;
 86 //===================
 87 procedure updata(x:longint);
 88 var
 89   i,j,p,s:longint;
 90 begin
 91   i:=pre(root,x); j:=suc(root,x);
 92   while (i>0) and not check(i,p,s) do
 93   begin
 94     delete(root,i);
 95     i:=p;
 96   end;
 97   while (j>0) and not check(j,p,s) do
 98   begin
 99     delete(root,j);
100     j:=s;
101   end;
102 end;
103 //===================
104 procedure insert(var k:longint; t:longint);
105 begin
106   if k=0 then
107   begin
108     inc(m);
109     s[m]:=t;
110     rand[m]:=random(maxlongint);
111     k:=m;
112     exit;
113   end;
114   if x[t]<x[s[k]]+zero then
115   begin
116     insert(l[k],t);
117     if rand[l[k]]>rand[k] then r_rotate(k);
118   end else
119   begin
120     insert(r[k],t);
121     if rand[r[k]]>rand[k] then l_rotate(k);
122   end;
123 end;
124 //===================
125 function find(k:longint; fk:double):longint;
126 var
127   k1,k2:double;
128   i,j:longint;
129 begin
130   if k=0 then exit(0);
131   i:=pre(root,s[k]); j:=suc(root,s[k]);
132   if i=0 then k1:=fk+1 else k1:=c_k(i,s[k]);
133   if j=0 then k2:=fk-1 else k2:=c_k(s[k],j);
134   if (k1>fk-zero)and(fk+zero>k2) then exit(s[k]) else
135   if (k1<fk-zero) then exit(find(l[k],fk)) else exit(find(r[k],fk));
136 end;
137 //===================
138 begin
139   assign(input,'cash.in'); reset(input);
140   assign(output,'cash.out'); rewrite(output);
141   randomize;
142   read(n,f[0]);
143   for i:=1 to n do read(a[i],b[i],rate[i]);
144   for i:=1 to n do
145   begin
146     j:=find(root,-a[i]/b[i]);
147     f[i]:=max(f[i-1],x[j]*a[i]+y[j]*b[i]);
148     y[i]:=f[i]/(rate[i]*a[i]+b[i]);
149     x[i]:=y[i]*rate[i];
150     if check(i,pp,ss) then insert(root,i);
151     updata(i);
152   end;
153   writeln(f[n]:0:3);
154   close(input); close(output);
155 end.

 

解法3:用平衡树优化DP(splay)
  1 (*
  2     Problem:    NOI2007 货币兑换
  3     Author:        Chen Yang
  4     Time:        2012.5.28 9:07 am
  5     State:        AC
  6     Memo:        斜率、splay优化DP
  7 *)
  8 program cash;
  9 uses math;
 10 const inf=1e9;
 11       zero=1e-8;
 12       maxn=100100;
 13 var
 14   n,root,i,j:longint;
 15   f,x,y,a,b,rate,lk,rk:array[0..maxn] of extended;
 16   l,r,father:array[0..maxn] of longint;
 17 //=======================
 18 procedure l_rotate(x:longint);
 19 var y,z:longint;
 20 begin
 21   y:=r[x]; z:=father[x];
 22   if x=l[z] then l[z]:=y else
 23   if x=r[z] then r[z]:=y;
 24   father[y]:=z; father[l[y]]:=x; father[x]:=y;
 25   r[x]:=l[y]; l[y]:=x; father[0]:=0;
 26 end;
 27 //=======================
 28 procedure r_rotate(x:longint);
 29 var y,z:longint;
 30 begin
 31   y:=l[x]; z:=father[x];
 32   if x=l[z] then l[z]:=y else
 33   if x=r[z] then r[z]:=y;
 34   father[y]:=z; father[r[y]]:=x; father[x]:=y;
 35   l[x]:=r[y]; r[y]:=x; father[0]:=0;
 36 end;
 37 //=======================
 38 procedure splay(x,p:longint);
 39 var y,z:longint;
 40 begin
 41   z:=father[p];
 42   while father[x]<>z do
 43   begin
 44     y:=father[x];
 45     if x=l[y] then r_rotate(y) else l_rotate(y);
 46   end;
 47   if p=root then root:=x;
 48 end;
 49 //=======================
 50 procedure insert(var k:longint; t,fa:longint);
 51 begin
 52   if k=0 then begin k:=t; father[t]:=fa; exit; end;
 53   if x[t]<x[k]+zero then insert(l[k],t,k) else insert(r[k],t,k);
 54 end;
 55 //=======================
 56 function c_k(i,j:longint):extended;
 57 begin
 58   if abs(x[i]-x[j])<zero then exit(-inf);
 59   exit((y[i]-y[j])/(x[i]-x[j]));
 60 end;
 61 //=======================
 62 function l_fix:longint;
 63 var x:longint;
 64 begin
 65   x:=l[root]; l_fix:=x;
 66   while x>0 do
 67   begin
 68     if c_k(x,root)<lk[x] then
 69     begin l_fix:=x; x:=r[x] end
 70     else x:=l[x];
 71   end;
 72 end;
 73 //=======================
 74 function r_fix:longint;
 75 var x:longint;
 76 begin
 77   x:=r[root]; r_fix:=x;
 78   while x>0 do
 79   begin
 80     if c_k(x,root)>rk[x] then
 81     begin r_fix:=x; x:=l[x] end
 82     else x:=r[x];
 83   end;
 84 end;
 85 //=======================
 86 procedure updata(x:longint);
 87 var t:longint;
 88 begin
 89   splay(x,root);
 90   if l[x]>0 then
 91   begin
 92     t:=l_fix; splay(t,l[x]); r[t]:=0;
 93     lk[x]:=c_k(l[x],x); rk[l[x]]:=lk[x];
 94   end else lk[x]:=inf;
 95   if r[x]>0 then
 96   begin
 97     t:=r_fix; splay(t,r[x]); l[t]:=0;
 98     rk[x]:=c_k(x,r[x]); lk[r[x]]:=rk[x];
 99   end else rk[x]:=-inf;
100   if lk[x]<rk[x]+zero then
101   begin
102     root:=l[x]; r[l[x]]:=r[x]; father[r[x]]:=l[x]; father[root]:=0;
103     rk[root]:=c_k(root,r[root]); lk[r[root]]:=rk[root];
104   end;
105 end;
106 //=======================
107 function find(x:longint; k:extended):longint;
108 begin
109   if x=0 then exit(0);
110   if (lk[x]+zero>k)and(k>rk[x]-zero) then exit(x);
111   if k>lk[x] then exit(find(l[x],k)) else exit(find(r[x],k));
112 end;
113 //=======================
114 begin
115   assign(input,'cash.in'); reset(input);
116   assign(output,'cash.out'); rewrite(output);
117   read(n,f[0]);
118   for i:=1 to n do read(a[i],b[i],rate[i]);
119   for i:=1 to n do
120   begin
121     j:=find(root,-a[i]/b[i]);
122     f[i]:=max(f[i-1],x[j]*a[i]+y[j]*b[i]);
123     y[i]:=f[i]/(rate[i]*a[i]+b[i]);
124     x[i]:=y[i]*rate[i];
125     insert(root,i,0);
126     updata(i);
127   end;
128   writeln(f[n]:0:3);
129   close(input); close(output);
130 end.

转载于:https://www.cnblogs.com/datam-cy/archive/2012/05/30/NOI2007-DAY1-HBDH.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值