【bzoj 1492】【codevs 1797】 [NOI2007]货币兑换Cash (dp+cdq分治)
1492: [NOI2007]货币兑换Cash
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 3803 Solved: 1604
[Submit][Status][Discuss]
Description
Input
Output
只有一个实数MaxProfit,表示第N天的操作结束时能够获得的最大的金钱数目。答案保留3位小数。
Sample Input
1 1 1
1 2 2
2 2 3
Sample Output
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分治)相关推荐
- 【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] ...
- bzoj千题计划237:bzoj1492: [NOI2007]货币兑换Cash
http://www.lydsy.com/JudgeOnline/problem.php?id=1492 dp[i] 表示 第i天卖完的最大收益 朴素的dp: 枚举从哪一天买来的在第i天卖掉,或者是不 ...
- 【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治
[BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每 ...
- [BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MB Submit: 5907 Solved: 2377 [Submit][S ...
- BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)
BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化) 1 #include<algorithm> 2 #include<iostream> 3 #include ...
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...
- [NOI2007]货币兑换Cash(DP+动态凸包)
第一次打动态凸包维护dp,感觉学到了超级多的东西. 首先,set是如此的好用!!!可以通过控制一个flag来实现两种查询,维护凸包和查找斜率k 不过就是重载运算符和一些细节方面有些恶心,90行解决 后 ...
- bzoj1492 [NOI2007]货币兑换Cash (斜率DP+cdq分治)
题意:到处都找得到. 我没看错的话当年考试的时候的题面里头,是提示了买卖一定是全部买入和卖出的.这样一来就好办了.cdq的论文里面那个F并不是她所说的那样,而是就是那个最优值.方程转移的时候实际上是枚 ...
- bzoj1492: [NOI2007]货币兑换Cash
码了我两个星期的题啊,终于写完了,感觉一半的时间都在调splay,后面写cdq好像轻松一点,cdq码量小一倍,而且又好想(可能是我调的时候理解了)感觉这种黑科技很nb,关键是可以减少细节出错(像我这种 ...
最新文章
- [教程]Python函数的参数
- Linux压缩解压缩文章总结
- WinForm-SuspendLayout、ResumeLayout、PerformLayou——转载
- .Net环境下的缓存技术介绍 (转)
- R软件中 文本分析安装包 Rjava 和 Rwordseg 傻瓜式安装方法四部曲
- 安防监控系统CIF、D1等格式的解释
- commit git 删除文件夹_从Git提交中删除文件
- matlab二重积分计算程序,MATLAB在二重积分计算中的应用
- 学python自学多久_python自学要多久能学会
- win2000上安装sql server 2000个人版时
- [深度学习] (sklearn)多层感知机对葡萄酒的分类
- 58沈剑_一分钟专栏
- 【基础】代码操作Word时,自动更新目录(一)
- 自己对PID控制算法的一点见解
- 浏览器下载文件,读取BLOB字段会因为数据太大导致数据库连接connect超时关闭的解决方案...
- 做人得厚道,不是么?
- 【漫漫长征路】hihocoder #1082 然而沼跃鱼早就看穿了一切
- 计算机研究生青岛就业,2017年就业形势严峻!青岛大学毕业生怎么样?都去哪儿了?...
- TOPSIS模型原理和MATLAB代码实现
- 【面试题】8.Redis相关