1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 3803  Solved: 1604
[Submit][Status][Discuss]

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位小数。

Sample Input

3 100
1 1 1
1 2 2
2 2 3

Sample Output

225.000

HINT

Source

[Submit][Status][Discuss]

【题解】【dp+cdq分治】

【这道题,先贪心的考虑,如果要最大,那么每一天一定只有一种操作,我们用f[i]表示第i天将所有的钱全部兑换成A, B券,最多可以得到多少A券】

【首先,它是一道dp。方程:f[i]=max{f[j]/(a[j]*rate[j]+b[j])*rate[j]*a[i]+f[j]/(a[j]*rate[j]+b[j])*b[i]}    O(n^2)】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
double A[100010],B[100010],rate[100010];
double f[100010],ans;
int n,s;
int main()
{int i,j;scanf("%d%d",&n,&s);for(i=1;i<=n;++i) scanf("%lf%lf%lf",&A[i],&B[i],&rate[i]);ans=s; f[1]=s*rate[1]/(A[1]*rate[1]+B[1]);for(i=2;i<=n;++i){for(j=1;j<i;++j)ans=max(ans,f[j]*A[i]+f[j]/rate[j]*B[i]);f[i]=ans*rate[i]/(A[i]*rate[i]+B[i]);}printf("%.3lf\n",ans);return 0;
}

【然而,范围辣么大,必然TLE啊!!!】

【我们再来研究下方程,首先用x,y分别代表A券和B券卖出的数量,发现它就是f[i]=x*A[i]+y*B[i]。然后又因为x/y=rate[i] —>y=x/rate[i],所以,方程变成了:f[i]=x*A[i]+x/rate[i]*B[i]—>f[i]*rate[i]=x*rate[i]*A[i]+x*B[i],所以第i天卖出的A券的数量x[i]=f[i]*rate[i]/(rate[i]*A[i]+B[i]),第i天卖出的B券的数量y[i]=f[i]/(rate[i]*A[i]+B[i]),so,回归到原方程,即f[i]=x[i]*A[i]+y[i]*B[i]—>y[i]=f[i]/B[i]-(A[i]/B[i])*x[i],这时我们惊奇地会发现,若想要f[i]最大,那么就是求一条过(x[i],y[i])且斜率为-A[i]/B[i]的直线的最大截距。好了,现在它是一道斜率优化dp...】

【我们可以发现,(x[i],y[i])在凸壳上,使用上凸壳来维护,怎么维护?splay?!(我仿佛看见了二三百行的代码。。。)这里使用一种神奇的方法cdq分治:首先,把斜率按从大到小排序,由于l-mid区间的斜率会对mid+1-r区间的斜率产生影响,所以,在处理每个区间时,把当前区间中num<=mid的操作分出来作为左区间,然后递归,左区间计算完后可以用来更新右区间,更新右区间时,要按斜率递减的方式更新,这样一边就可以处理好全部的,然后再递归。】

【最后,将两个区间的最优值利用归并排序重新排序,返回上一层】

#include<cmath>>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define eps 1e-9
using namespace std;
struct slove{double a,b,k,rate;double x,y;int num;
}d[100010],p[100010];
double f[100010];//f[i]表示第i天将所有的钱全部兑换成A, B券,最多可以得到多少A券
int n,que[100010],t;
int tmp(slove a,slove b)
{return a.k>b.k;
}
inline double check(int i,int j)
{if(!j) return -1e20;if(fabs(d[i].x-d[j].x)<eps) return 1e20;return (d[j].y-d[i].y)/(d[j].x-d[i].x);
}
inline void cdq(int l,int r)
{if(l==r){if(f[l]<f[l-1]) f[l]=f[l-1];d[l].y=f[l]/(d[l].a*d[l].rate+d[l].b);d[l].x=d[l].y*d[l].rate;return;}int mid=(l+r)>>1,pl=l,pr=mid+1;for(int i=l;i<=r;++i) if(d[i].num<=mid) p[pl++]=d[i];else p[pr++]=d[i];for(int i=l;i<=r;++i) d[i]=p[i];//把当前区间更新为按读入顺序为关键字排序cdq(l,mid);t=0;for(int i=l;i<=mid;++i){while(t>=2&&check(que[t-1],que[t])<check(que[t-1],i)+eps) t--;que[++t]=i;}que[++t]=0;//左区间维护凸包int j=1;for(int i=mid+1;i<=r;++i){while(j<t&&check(que[j],que[j+1])+eps>d[i].k) ++j;f[d[i].num]=max(f[d[i].num],d[que[j]].x*d[i].a+d[que[j]].y*d[i].b);}//用左区间的点作为决策更新右区间 cdq(mid+1,r);pl=l; pr=mid+1;for(int i=l;i<=r;++i)if(((d[pl].x<d[pr].x||fabs(d[pl].x-d[pr].x)<eps&&d[pl].y<d[pr].y)||pr>r)&&pl<=mid) p[i]=d[pl++];else p[i]=d[pr++];for(int i=l;i<=r;++i) d[i]=p[i];//把当前区间更新为以a卷数量为关键字排序
}
int main()
{int i;scanf("%d%lf",&n,&f[0]);for(i=1;i<=n;++i){scanf("%lf%lf%lf",&d[i].a,&d[i].b,&d[i].rate);d[i].k=-d[i].a/d[i].b; d[i].num=i;}sort(d+1,d+n+1,tmp);cdq(1,n);printf("%.3lf\n",f[n]);return 0;
}

转载于:https://www.cnblogs.com/lris-searching/p/9403080.html

【bzoj 1492】【codevs 1797】 [NOI2007]货币兑换Cash (dp+cdq分治)相关推荐

  1. 【BZOJ1492】【NOI2007】—Cash(cdq分治维护凸包优化斜率dp)

    传送门 考虑令f[i]f[i]f[i]为第iii天得到的最多的AAA券,g[i]g[i]g[i]为第iii天得到的最多的BBB券 则g[i]=f[i]/rate[i]g[i]=f[i]/rate[i] ...

  2. bzoj千题计划237:bzoj1492: [NOI2007]货币兑换Cash

    http://www.lydsy.com/JudgeOnline/problem.php?id=1492 dp[i] 表示 第i天卖完的最大收益 朴素的dp: 枚举从哪一天买来的在第i天卖掉,或者是不 ...

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

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

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

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

  5. BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)

    BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化) 1 #include<algorithm> 2 #include<iostream> 3 #include ...

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

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

  7. [NOI2007]货币兑换Cash(DP+动态凸包)

    第一次打动态凸包维护dp,感觉学到了超级多的东西. 首先,set是如此的好用!!!可以通过控制一个flag来实现两种查询,维护凸包和查找斜率k 不过就是重载运算符和一些细节方面有些恶心,90行解决 后 ...

  8. bzoj1492 [NOI2007]货币兑换Cash (斜率DP+cdq分治)

    题意:到处都找得到. 我没看错的话当年考试的时候的题面里头,是提示了买卖一定是全部买入和卖出的.这样一来就好办了.cdq的论文里面那个F并不是她所说的那样,而是就是那个最优值.方程转移的时候实际上是枚 ...

  9. bzoj1492: [NOI2007]货币兑换Cash

    码了我两个星期的题啊,终于写完了,感觉一半的时间都在调splay,后面写cdq好像轻松一点,cdq码量小一倍,而且又好想(可能是我调的时候理解了)感觉这种黑科技很nb,关键是可以减少细节出错(像我这种 ...

最新文章

  1. [教程]Python函数的参数
  2. Linux压缩解压缩文章总结
  3. WinForm-SuspendLayout、ResumeLayout、PerformLayou——转载
  4. .Net环境下的缓存技术介绍 (转)
  5. R软件中 文本分析安装包 Rjava 和 Rwordseg 傻瓜式安装方法四部曲
  6. 安防监控系统CIF、D1等格式的解释
  7. commit git 删除文件夹_从Git提交中删除文件
  8. matlab二重积分计算程序,MATLAB在二重积分计算中的应用
  9. 学python自学多久_python自学要多久能学会
  10. win2000上安装sql server 2000个人版时
  11. [深度学习] (sklearn)多层感知机对葡萄酒的分类
  12. 58沈剑_一分钟专栏
  13. 【基础】代码操作Word时,自动更新目录(一)
  14. 自己对PID控制算法的一点见解
  15. 浏览器下载文件,读取BLOB字段会因为数据太大导致数据库连接connect超时关闭的解决方案...
  16. 做人得厚道,不是么?
  17. 【漫漫长征路】hihocoder #1082 然而沼跃鱼早就看穿了一切
  18. 计算机研究生青岛就业,2017年就业形势严峻!青岛大学毕业生怎么样?都去哪儿了?...
  19. TOPSIS模型原理和MATLAB代码实现
  20. 【面试题】8.Redis相关

热门文章

  1. Curved-Voxel Clustering 曲率体素聚类点云分割
  2. 2022-2028年全球管理交换机行业供需分析及发展前景研究报告
  3. soundtouch源码分析
  4. Python修改文件的两种方法
  5. Android应用层View绘制流程与源码分析
  6. Bootstrap 实例 2 中型大型设备
  7. layui当前表格第一行_layui使用表格渲染获取行数据的例子
  8. Adobe Audition CC初学者完整教程
  9. java js 二级联动下拉列表_二级联动下拉列表JS+html实现
  10. day 53-1 Django基础三之视图函数