【NOI2007】 货币兑换
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
货币兑换 问题描述 小 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、 分别表示小 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 第一天 买入 100 元 0 50 50 第二天 卖出 100% 150 0 0 第二天 买入 150 元 0 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; 提示 输入文件可能很大,请采用快速的读入方式。 必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币; 每次卖出操作卖出所有的金券。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.