Description

小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 的变化分别为:
假定在第一天时,用户手中有 100元 人民币但是没有任何金券。用户可以执行以下的操作:
注意到,同一天内可以进行多次操作。小Y是一个很有经济头脑的员工,通过较长时间的运作和行情测算,他已经
知道了未来N天内的A券和B券的价值以及Rate。他还希望能够计算出来,如果开始时拥有S元钱,那么N天后最多能
够获得多少元钱。

Input

输入第一行两个正整数N、S,分别表示小Y能预知的天数以及初始时拥有的钱数。接下来N行,第K行三个实数AK、B
K、RateK,意义如题目中所述。对于100%的测试数据,满足:0<AK≤10;0<BK≤10;0<RateK≤100;MaxProfit≤1
0^9。
【提示】
1.输入文件可能很大,请采用快速的读入方式。
2.必然存在一种最优的买卖方案满足:
每次买进操作使用完所有的人民币;
每次卖出操作卖出所有的金券。
 

Output

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

题解: 令 $f_{i}$ 表示第 $i$ 天所拥有的最大钱数

贪心猜到对于 $A,B$ 不是全部买进就是全部卖出
那么,第 $j$ 天所拥有的 $A$ 券 $x_{j}=\frac{f_{j}R_{j}}{a_{j}R_{j}+b_{j}}$, $B$ 券 $y_{j}=\frac{f_{j}}{a_{j}R_{j}+b_{j}}$
得 $f_{i}\Rightarrow x_{j}a_{i}+y_{j}b_{i}$
将方程写成一次函数的形式:$y_{j}=-\frac{a_{i}}{b_{i}}x_{j}+\frac{f_{i}}{b_{i}}$
对于 $i$来说 $a_{i},b_{i}$ 都是固定的,即斜率是一定的
将 $(x_{j},y_{j})$ 视为二维平面中的点,$f_{i}$ 最大化就是要让斜率为 $-\frac{a_{i}}{b_{i}}$ 的直线获得最大的截距
然而,斜率不是单调的,新加入点的横坐标($x_{i}$)也不是单调的,所以只能用平衡树来动态维护这个凸包.
需要支持插入一个点,查询一个直线所经过的最优点.
具体细节看代码,思路简单,代码不好写
  1. #include<bits/stdc++.h>
  2. #define maxn 300000
  3. #define inf 0x3f3f3f3f
  4. #define setIO(s) freopen(s".in","r",stdin)
  5. using namespace std;
  6. const double eps = 1e-9;
  7. int root;
  8. struct Splaytree
  9. {
  10. #define get(x) (ch[f[x]][1]==x)
  11. int cnt;
  12. int f[maxn],ch[maxn][2];
  13. double X[maxn],Y[maxn],lk[maxn],rk[maxn];
  14. inline void rotate(int x)
  15. {
  16. int old=f[x],fold=f[old],which=get(x);
  17. ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
  18. ch[x][which^1]=old,f[old]=x,f[x]=fold;
  19. if(fold) ch[fold][ch[fold][1]==old]=x;
  20. }
  21. inline void splay(int x,int &tar)
  22. {
  23. int fa,u=f[tar];
  24. for(;(fa=f[x])!=u;rotate(x))
  25. if(f[fa]!=u)
  26. rotate(get(fa)==get(x)?fa:x);
  27. tar=x;
  28. }
  29. inline double slope(int i,int j)
  30. {
  31. return fabs(X[i]-X[j])<=eps ? -inf : (Y[i]-Y[j])/(X[i]-X[j]);
  32. }
  33. inline void insert(int &o,double x,double y,int last)
  34. {
  35. if(!o)
  36. {
  37. o=++cnt;
  38. X[o]=x,Y[o]=y,f[o]=last;
  39. return;
  40. }
  41. insert(ch[o][x-X[o]>eps],x,y,o);
  42. }
  43. inline int pre(int x)
  44. {
  45. int cur=ch[x][0],re=0;
  46. while(cur)
  47. {
  48. if(slope(x,cur)+eps>=rk[cur]) re=cur,cur=ch[cur][0];
  49. else cur=ch[cur][1];
  50. }
  51. return re;
  52. }
  53. inline int nxt(int x)
  54. {
  55. int cur=ch[x][1],re=0;
  56. while(cur)
  57. {
  58. if(slope(x,cur)<=lk[cur]+eps) re=cur,cur=ch[cur][1];
  59. else cur=ch[cur][0];
  60. }
  61. return re;
  62. }
  63. inline int getl(int x)
  64. {
  65. while(ch[x][0]) x=ch[x][0];
  66. return x;
  67. }
  68. inline int getr(int x)
  69. {
  70. while(ch[x][1]) x=ch[x][1];
  71. return x;
  72. }
  73. inline void del(int x)
  74. {
  75. if(!ch[x][0])
  76. {
  77. int right=getl(ch[x][1]);
  78. splay(right,ch[x][1]),root=right;
  79. ch[x][1]=f[root]=0;
  80. lk[root]=inf;
  81. }
  82. else if(!ch[x][1])
  83. {
  84. int left=ch[x][0];
  85. splay(left,ch[x][0]),root=left;
  86. ch[x][0]=f[root]=0;
  87. rk[root]=-inf;
  88. }
  89. else
  90. {
  91. int right=getl(ch[x][1]);
  92. int left=getr(ch[x][0]);
  93. splay(left,ch[x][0]);
  94. splay(right,ch[x][1]);
  95. root=left;
  96. ch[root][1]=right,f[right]=root;
  97. rk[root]=lk[right]=slope(root,right);
  98. }
  99. }
  100. inline void maintain(int x)
  101. {
  102. splay(x,root);
  103. if(ch[x][0])
  104. {
  105. int left=pre(x);
  106. if(left)
  107. {
  108. splay(left,ch[x][0]);
  109. ch[left][1]=f[ch[left][1]]=0;
  110. rk[left]=lk[x]=slope(left,x);
  111. }
  112. else lk[x]=-inf;
  113. }
  114. else lk[x]=inf;
  115. if(ch[x][1])
  116. {
  117. int right=nxt(x);
  118. if(right)
  119. {
  120. splay(right,ch[x][1]);
  121. ch[right][0]=f[ch[right][0]]=0;
  122. rk[x]=lk[right]=slope(right,x);
  123. }
  124. else rk[x]=inf;
  125. }
  126. else rk[x]=-inf;
  127. if(lk[x]-rk[x]<=eps) del(x);
  128. }
  129. inline int getans(int x,double k)
  130. {
  131. if(!x) return 0;
  132. if(lk[x]+eps>=k&&rk[x]<=k+eps) return x;
  133. if(lk[x]<k+eps) return getans(ch[x][0],k);
  134. else return getans(ch[x][1],k);
  135. }
  136. }splay;
  137. int n,S;
  138. double f[maxn],A[maxn],B[maxn],rate[maxn];
  139. int main()
  140. {
  141. int i,j;
  142. // setIO("input");
  143. scanf("%d%lf",&n,&f[0]);
  144. for(i=1;i<=n;++i)
  145. {
  146. scanf("%lf%lf%lf",&A[i],&B[i],&rate[i]);
  147. int j=splay.getans(root,-(A[i]/B[i]));
  148. double x=splay.X[j],y=splay.Y[j];
  149. f[i]=max(f[i-1],A[i]*x+B[i]*y);
  150. y=f[i]/(A[i]*rate[i]+B[i]);
  151. x=y*rate[i];
  152. splay.insert(root,x,y,0);
  153. splay.maintain(i);
  154. }
  155. printf("%.3lf",f[n]);
  156. return 0;
  157. }

  

BZOJ 1492: [NOI2007]货币兑换Cash 斜率优化 + splay动态维护凸包的更多相关文章

  1. [BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包

    1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5907  Solved: 2377[Submit][Sta ...

  2. BZOJ.1492.[NOI2007]货币兑换(DP 斜率优化 CDQ分治/Splay)

    BZOJ 洛谷 如果某天能够赚钱,那么一定会在这天把手上的金券全卖掉.同样如果某天要买,一定会把所有钱花光. 那么令\(f_i\)表示到第\(i\)天所拥有的最多钱数(此时手上没有任何金券),可以选择 ...

  3. BZOJ 3963: [WF2011]MachineWorks 斜率优化 + splay动态维护凸包

    Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器.原来的那一台生产机器已经坏了,所以 ...

  4. BZOJ 1492 [NOI2007]货币兑换Cash (CDQ分治/splay 维护凸包)

    题目大意:太长了略 splay调了两天一直WA弃疗了 首先,我们可以猜一个贪心,如果买/卖,就一定都买/卖掉,否则不买/卖 反正货币的行情都是已知的,没有任何风险,所以肯定要选择最最最优的方案了 容易 ...

  5. [BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)

    1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5838  Solved: 2345[Submit][Sta ...

  6. BZOJ 1492: [NOI2007]货币兑换Cash( dp + 平衡树 )

    dp(i) = max(dp(i-1), x[j]*a[i]+y[j]*b[i]), 0<j<i. x, y表示某天拥有的最多钱去买金券, 金券a和金券b的数量. 然后就很明显了...平衡 ...

  7. 【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治

    [BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每 ...

  8. BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]

    传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...

  9. 【BZOJ 1492】 [NOI2007]货币兑换Cash 斜率优化DP

    先说一下斜率优化:这是一种经典的dp优化,是OI中利用数形结合的思想解决问题的典范,通常用于优化dp,有时候其他的一些决策优化也会用到,看待他的角度一般有两种,但均将决策看为二维坐标系上的点,并转化为 ...

随机推荐

  1. python-笔记-内置函数

    ###内置函数 print(all([1,2,3,4]))判断可迭代的对象里面的值是否都为真 print(any([0,1,2,3,4]))判断可迭代的对象里面的值是否有一个为真 print(id(l ...

  2. 002-js-cookie

    cookie操作方法 1.写cookie //JS操作cookies方法! //写cookies function setCookie(name,value) { var Days = 30; var ...

  3. KETTLE——(三)数据输出

    数据输出和数据输入基本差不多,KETTLE本身支持的数据输出方式也特别多,还是以数据库输出为例. ​ 打开表输出的界面,简单介绍一下其功能: ​ 就这个界面,如果不勾选[指定数据库字段],KETTLE ...

  4. Dnsmasq 安装配置

    Dnsmasq  官网 http://www.thekelleys.org.uk/dnsmasq/doc.html Unbuntu 安装 Dnsmasq 参见https://help.ubuntu.c ...

  5. Winform 开源控件库( Sheng.Winform.Controls)

    升讯威 .Net WinForm 控件库提供了超过15种 Winform 控件,你可以直接使用本控件库,更可以通过本控件库学到 Winform 控件开发的方法和理念. 你可以学习到: 如何基于 Con ...

  6. java 获取某路径下的子文件/子路径

    /** * 获取某路径下的子文件 * */ public static List<String> getSubFile(String path){ List<String> s ...

  7. 剑指Offer编程题(Java实现)——替换空格

    题目描述 请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 解题思路1 在字符串尾部填充任 ...

  8. 解决在data里面获取一个固定的img值

    正常情况下在data里面申明,在img标签里面通过 :src应用就行了,但是如果是直接申明引用是没效果的: html: <div class="logo"> <i ...

  9. swiper和tab相结合

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. apache2.4 只允许合法域名访问网站 禁止使用ip、非法域名访问

    1.ip访问禁用ip访问 只能对应端口有效<VirtualHost *:80> ServerName xx.xx.xx.xx ServerAlias * <Location /> ...