1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec  Memory Limit: 64 MB

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,意义如题目中所述。
测试数据设计使得精度误差不会超过10^-7。
对于40%的测试数据,满足N ≤10;
对于60%的测试数据,满足N ≤1 000;
对于100%的测试数据,满足N ≤100 000;
对于100%的测试数据,满足:0<AK≤10;0<BK≤10;0<RateK≤100;MaxProfit≤10^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

(转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/8028556.html )

终于把CDQ维护凸壳学了……

那么既然题目已经给提示2了,我们就可以针对性的设$f[i]$为第i天获得的最多A券数,$ans[i]$为第i天的最大获利,那么我们要求的就是ans[n]了。

这个dp显然是可以$O(n^{2})$解决的……但是这样拿不了后面的分数。

然后你就想啊,肯定要优化啊……然后你就可以化出一个斜率的式子来。

对于$ans[i]$的决策,我们设两天j和k,j比k优秀的话,就会有

$(f[j]-f[k])*a[i]+(f[j]/rate[j]-f[k]/rate[k])*b[i]>0$

再设$g[i]=f[i]/rate[i]$(也就是第i天获得的最多B券数),为了处理不等式的符号我们设$f[j]<f[k]$

所以有:

$(g[j]-g[k])*b[i]>-(f[j]-f[k])*a[i]$

$(g[j]-g[k])/(f[j]-f[k])<-a[i]/b[i]$

(当然,实际情况是有$f[j]==f[k]$,即斜率不存在的情况存在的,到时候还要讨论。)

那么我们转化到一些坐标为(f[i],g[i])的二维平面的点上来。

我们建立一个这些点的上凸壳,然后在凸壳上二分最靠左的最后一个满足$k(point(x),point(x+1))<-a[i]/b[i]$的点x,

那么$x+1$就是最优秀的取值,也即本次决策点。

但是你发现这个f[i]不随i单调……那么我们考虑splay或者CDQ

打个J的splay啊

那么我们CDQ维护凸壳并且决策就好了……

具体实现是让$f[i]$有序之后按照正常方法建凸壳,然后让$-a[i]/b[i]$有序(我是从大到小排序),单调扫一边完成决策。

怎么让这俩有序呢……一是大力sort,复杂度$O(nlog^{2}n)$,一是归并排序,复杂度$O(nlogn)$

两种方法我都打了一下……感觉少个$logn$没快到哪去,也没长到哪去……

如果复杂度可行还是打$log^{2}$吧……

两份代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. #define eps 1e-8
  6. #define N 100010
  7. #define db double
  8. #define inf 0x7fffffff
  9. #define sign(a) (((a)>-eps)-((a)<eps))
  10. int n,top,sta[N],id[N],tmp[N],idk[N],tmpk[N],match[N];
  11. db ans[N],ak[N],bk[N],rate[N],f[N],g[N];
  12. inline db max(db a,db b){return a>b?a:b;}
  13. inline bool comp(const int &a,const int &b)
  14. {return f[a]<f[b] || ( sign(f[a]-f[b])==&&g[a]<g[b] );}
  15. inline double k(int a,int b)
  16. {
  17. if(sign(f[a]-f[b])==)return sign(g[a]-g[b])*inf;
  18. return (g[a]-g[b])/(f[a]-f[b]);
  19. }
  20. inline bool compk(const int &a,const int &b)
  21. {return sign( (-ak[a]/bk[a]) - (-ak[b]/bk[b]) ) > ;}
  22. inline void CDQ(int l,int r)
  23. {
  24. if(l==r){g[l]=f[l]/rate[l];return;}
  25. register int hd1,i,t,mi=l+r>>,p=l-,q=mi,h=l-;
  26. for(i=l;i<=r;++i)
  27. if(match[idk[i]]<=mi)tmpk[++p]=idk[i];
  28. else tmpk[++q]=idk[i];
  29. for(i=l;i<=r;++i)idk[i]=tmpk[i];
  30. CDQ(l,mi);
  31. for(top=,i=l;i<=mi;++i)
  32. {
  33. while(top> && k(sta[top-],sta[top]) < k(sta[top],id[i]) )--top;
  34. sta[++top]=id[i];
  35. }
  36. for(hd1=,i=mi+;i<=r;++i)
  37. {
  38. t=match[idk[i]];
  39. while( hd1<top&&sign( k(sta[hd1],sta[hd1+]) - (-ak[t]/bk[t]) ) >= )++hd1;
  40. ans[t]=max(ans[t],f[sta[hd1]]*ak[t]+g[sta[hd1]]*bk[t]);
  41. }
  42. for(i=mi+;i<=r;++i)
  43. t=match[idk[i]],ans[t]=max(ans[t],ans[t-]),f[t]=ans[t]*rate[t]/(ak[t]*rate[t]+bk[t]);
  44. CDQ(mi+,r);
  45. p=l,q=mi+,h=l;
  46. while(p<=mi&&q<=r)
  47. if(comp(id[p],id[q]))tmp[h++]=id[p++];
  48. else tmp[h++]=id[q++];
  49. while(p<=mi)tmp[h++]=id[p++];
  50. while(q<=r)tmp[h++]=id[q++];
  51. for(i=l;i<=r;++i)id[i]=tmp[i];
  52. }
  53. int main()
  54. {
  55. register int i,j;
  56. scanf("%d%lf",&n,&ans[]);
  57. for(i=;i<=n;++i)
  58. scanf("%lf%lf%lf",&ak[i],&bk[i],&rate[i]);
  59. f[]=ans[]*rate[]/(ak[]*rate[]+bk[]);
  60. for(i=;i<=n;++i)id[i]=idk[i]=match[i]=i;
  61. sort(match+,match+n+,compk);
  62. CDQ(,n);
  63. printf("%.3f\n",ans[n]);
  64. }

nlogn

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. #define eps 1e-8
  6. #define N 100010
  7. #define db double
  8. #define inf 0x7fffffff
  9. #define sign(a) (((a)>-eps)-((a)<eps))
  10. int n;
  11. db ans[N],ak[N],bk[N],rate[N],f[N],g[N];
  12. inline db max(db a,db b){return a>b?a:b;}
  13. int top,sta[N];
  14. int id[N],tmp[N],idk[N];
  15. inline bool comp(const int &a,const int &b)
  16. {
  17. return f[a]<f[b] || ( sign(f[a]-f[b])==&&g[a]<g[b] );
  18. }
  19. inline double k(int a,int b)
  20. {
  21. if(sign(f[a]-f[b])==)
  22. return sign(g[a]-g[b])*inf;
  23. return (g[a]-g[b])/(f[a]-f[b]);
  24. }
  25. inline bool compk(const int &a,const int &b)
  26. {
  27. return sign( (-ak[a]/bk[a]) - (-ak[b]/bk[b]) ) > ;
  28. }
  29. inline void CDQ(int l,int r)
  30. {
  31. if(l==r){g[l]=f[l]/rate[l];return;}
  32. register int hd1,i,mi=l+r>>;
  33. CDQ(l,mi);
  34. for(i=mi+;i<=r;++i)id[i]=i;sort(id+l,id+mi+,comp);
  35. for(i=mi+;i<=r;++i)idk[i]=i;sort(idk+mi+,idk+r+,compk);
  36. for(top=,i=l;i<=mi;++i)
  37. {
  38. while(top> && k(sta[top-],sta[top]) < k(sta[top],id[i]) )--top;//****
  39. sta[++top]=id[i];
  40. }
  41. for(hd1=,i=mi+;i<=r;++i)
  42. {
  43. while( hd1<top&&sign( k(sta[hd1],sta[hd1+]) - (-ak[idk[i]]/bk[idk[i]]) ) >= )++hd1;
  44. ans[idk[i]]=max(ans[idk[i]],f[sta[hd1]]*ak[idk[i]]+g[sta[hd1]]*bk[idk[i]]);
  45. }
  46. for(i=mi+;i<=r;++i)
  47. ans[i]=max(ans[i],ans[i-]),f[i]=ans[i]*rate[i]/(ak[i]*rate[i]+bk[i]);
  48. CDQ(mi+,r);
  49. }
  50. int main()
  51. {
  52. register int i,j;
  53. scanf("%d%lf",&n,&ans[]);
  54. for(i=;i<=n;++i)
  55. scanf("%lf%lf%lf",&ak[i],&bk[i],&rate[i]);
  56. f[]=ans[]*rate[]/(ak[]*rate[]+bk[]);
  57. for(i=;i<=n;++i)id[i]=i;
  58. CDQ(,n);
  59. printf("%.3f\n",ans[n]);
  60. }

nlog^2n

BZOJ1492 货币兑换 CDQ分治优化DP的更多相关文章

  1. 洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP

    洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他. 玩具上有一个数列,数列中某些项的值可能会 ...

  2. SPOJ LIS2 - Another Longest Increasing Subsequence Problem(CDQ分治优化DP)

    题目链接  LIS2 经典的三维偏序问题. 考虑$cdq$分治. 不过这题的顺序应该是 $cdq(l, mid)$ $solve(l, r)$ $cdq(mid+1, r)$ 因为有个$DP$. #i ...

  3. luogu4093 序列 (cdq分治优化dp)

    设f[i]是以i位置为结尾的最长满足条件子序列的长度 那么j能转移到i的条件是,$j<i , max[j]<=a[i] , a[j]<=min[i]$,其中max和min表示这个位置 ...

  4. P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)

    P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...

  5. [NOI2007]货币兑换 cdq分治,斜率优化

    [NOI2007]货币兑换 LG传送门 妥妥的\(n \log n\)cdq做法. 这题用cdq分治也可以\(n \log n\)但是在洛谷上竟然比一些优秀的splay跑得慢真是见了鬼了看来还是人丑常 ...

  6. 【BZOJ1492】【Luogu P4027】 [NOI2007]货币兑换 CDQ分治,平衡树,动态凸包

    斜率在转移顺序下不满足单调性的斜率优化\(DP\),用动态凸包来维护.送命题. 简化版题意:每次在凸包上插入一个点,以及求一条斜率为\(K\)的直线与当前凸包的交点.思路简单实现困难. \(P.s\) ...

  7. BZOJ3963: [WF2011]MachineWorks 【CDQ+斜率优化DP】*

    BZOJ3963: [WF2011]MachineWorks Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先 ...

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

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

  9. SRM12 T2夏令营(分治优化DP+主席树 (已更新NKlogN)/ 线段树优化DP)

     先写出朴素的DP方程f[i][j]=f[k][j-1]+h[k+1][i] {k<i}(h表示[k+1,j]有几个不同的数)  显然时间空间复杂度都无法承受   仔细想想可以发现对于一个点 i ...

随机推荐

  1. redis系列--你真的入门了吗?redis4.0入门~

    前言 redis作为nosql家族中非常热门的一员,也是被大型互联网公司所青睐,无论你是开发.测试或者运维,学习掌握它总会为你的职业生涯增色添彩. 当然,你或多或少已经了解redis,但是你是否了解其 ...

  2. Kubernetes学习之路目录

    Kubernetes基础篇 环境说明 版本说明 系统环境 Centos 7.2 Kubernetes版本 v1.11.2 Docker版本 v18.09 Kubernetes学习之路(一)之概念和架构 ...

  3. LeetCode 4Sum (Two pointers)

    题意 Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = ...

  4. vue初学实践之路——vue简单日历组件(2)

    上一篇我们已经实现了基本的日历显示功能,这一次我们要加上预定的功能 废话不多说,上代码 <div id="calendar"> <!-- 年份 月份 --> ...

  5. npm install —— 从一个简单例子,看本地安装与全局安装的区别

    npm的包安装分为本地安装(local).全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,比如 npm install grunt # 本地安装 npm install -g ...

  6. Zookeeper 通知更新可靠吗? 解读源码找答案!

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由特鲁门发表于云+社区专栏 导读: 遇到Keepper通知更新无法收到的问题,思考节点变更通知的可靠性,通过阅读源码解析了解到zk Wa ...

  7. 部署jar项目常用命令

      netstat -tunlp | grep  ××   查询出端口为××在运行应用的线程ip   kill -9  ××     关闭线程ip 为 ××的应用   rm  -f  ××.jar  ...

  8. LintCode——旋转字符串

    描述:给定一个字符串和一个偏移量,根据偏移量旋转字符串(从左向右旋转) 样例:对于字符串 "abcdefg"     offset=0 => "abcdefg&qu ...

  9. 【转载】python %s %d %f

    %s 字符串 string="hello" #%s打印时结果是hello print "string=%s" % string      # output: s ...

  10. 普通程序员看k8s的账户管理

    一.知识准备 ● 账户管理分为:userAccount与serviceAccount ● userAccount:通常是给人设计使用的,并且userAccount不在k8s集群内管理 ● servic ...