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

题面

分析

dp方程推导

显然,必然存在一种最优的买卖方案满足:每次买进操作使用完所有的人民币;每次卖出操作卖出所有的金券.

设dp[i]表示第i天卖出所有金券的能够得到的钱数。则有:

\[dp[i]=max(dp[i-1],\frac{dp[j]}{A[j] \times R[j]+B[j] } \times (A[i] \times R[j]+B[i])) (0 \leq j < i)
\]

意义是第j天按R[j]的比例用所有钱买入股票,然后在第i天全部卖出,比例仍为R[j]

去掉max,把i,j分开移项,得

\[dp[i]=\frac{dp[j]}{A[j] \times R[j]+B[j] } \times B[i]+\frac{dp[j] \times R[j]}{A[j] \times R[j]+B[j] } \times A[i]
\]

令\(x[j]=\frac{dp[j]}{A[j] \times R[j]+B[j] }\),\(y[j]=\frac{dp[j] \times R[j]}{A[j] \times R[j]+B[j] }\)

那么状态转移方程就变成了\(dp[i]=x[j] \times B[i]+y[j] \times A[i]\)

变换成直线方程的形式,y[j]前面有个系数A[i],把它除掉,得

\[y[j]=-\frac{B[i]}{A[i]} \times x[j]+dp[i]
\]

因此用斜率为\(-\frac{B[i]}{A[i]}\)的直线经过点\((x[j],y[j])\),解出的最小截距就是\(dp[i]\)的值。注意到\(-\frac{B[i]}{A[i]}\)和x[j]并不单调,不能用单调队列优化。考虑cdq分治求解

cdq 分治

cdq分治求解斜率优化其实类似一个三维偏序过程,第一维是点i对应的直线斜率(本题中是\(-\frac{B[i]}{A[i]}\)),第二,三维是对应的点的坐标

首先在cdq分治的时候需要维护一个数组a,记录a对应的dp值下标id,和它对应点的坐标。先把a按直线斜率排序,然后开始cdq分治。

当我们分治到区间[l,r]的时候,我们执行以下伪代码

procedure CDQ(l,r){
if(l==r){
用a[l]对应的dp值来更新a的(x,y)
return
}
mid=(l+r)/2
把[l,r]内的元素按id分成两个区间,id<=mid的分到[l,mid],否则分到[mid+1,r]
CDQ(l,mid),先递归计算id值小的
把[l,mid]区间对应的点建出凸壳,用于下一步更新[mid+1,r]的dp值
for(k in [mid+1,r]){
用单调队列更新a[k]对应的dp值,因为我们cdq之前按斜率排过序,所以不会出问题
注意到在这里面即使a[k]对应的dp值的最优决策不在[mid+1,r]中,那么回溯到一个更大的区间后,也会被更新到
}
CDQ(mid+1,r),继续递归下去更新
按x,y归并排序[l,mid],[mid+1,r],这样回溯的时候x单调递增,才可以直接单调栈(队列)建凸壳
}

注意精度问题,以及斜率为\(+ ∞\)的情况

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define eps 1e-8
#define INF 1e18
#define maxn 100000
using namespace std;
typedef long long ll;
typedef double db;
int n;
db S;
db A[maxn+5],B[maxn+5],R[maxn+5];
struct Vector{
int id;
db x;
db y;
Vector(){ }
Vector(int _id,db _x,db _y){
id=_id;
x=_x;
y=_y;
}
}a[maxn+5];
typedef Vector point;
db slope(point p,point q){
db down=p.x-q.x;
db up=p.y-q.y;
if(fabsl(down)<=eps) return INF;
else return up/down;
} int cmp1(point p,point q){
db k1=(fabs(A[p.id])>eps)?-B[p.id]/A[p.id]:INF;
db k2=(fabs(A[q.id])>eps)?-B[q.id]/A[q.id]:INF;
return k1<k2;//按斜率排序,保证斜率单调
}
int cmp2(point p,point q){//按x,y归并排序
if(p.x==q.x) return p.y<q.y;
else return p.x<q.x;
} int head,tail;
point q[maxn+5];
point tmp[maxn+5];
db dp[maxn+5]; db get_x(int j){
return dp[j]/(A[j]*R[j]+B[j]);
}
db get_y(int j){
return dp[j]*R[j]/(A[j]*R[j]+B[j]);
}
void cdq_divide(int l,int r){
if(l==r){
dp[a[l].id]=max(dp[a[l].id],dp[a[l].id-1]);
a[l].x=get_x(a[l].id);
a[l].y=get_y(a[l].id);
return;
}
int mid=(l+r)>>1;
int pl=l,pr=mid+1;
for(int i=l;i<=r;i++){
if(a[i].id<=mid) tmp[pl++]=a[i];
else tmp[pr++]=a[i];
}
for(int i=l;i<=r;i++) a[i]=tmp[i]; cdq_divide(l,mid);
head=1,tail=0;
for(int i=l;i<=mid;i++){
while(head<tail&&slope(q[tail-1],q[tail])<=slope(q[tail-1],a[i])) tail--;
q[++tail]=a[i];
} for(int k=r;k>mid;k--){//由于是维护上凸壳,斜率从小到大排,要倒序更新
int i=a[k].id;
db s2=(fabs(A[i])>eps)?-B[i]/A[i]:INF;
while(head<tail&&slope(q[head],q[head+1])>=s2) head++;
int j=q[head].id;
dp[i]=max(dp[i],A[i]*get_y(j)+B[i]*get_x(j));
// dp[i]=max(dp[i],dp[i-1]);
}
cdq_divide(mid+1,r); int num=l-1;
pl=l,pr=mid+1;
while(pl<=mid&&pr<=r){//按x,y归并排序
if(cmp2(a[pl],a[pr])) tmp[++num]=a[pl++];
else tmp[++num]=a[pr++];
}
while(pl<=mid) tmp[++num]=a[pl++];
while(pr<=r) tmp[++num]=a[pr++];
for(int i=l;i<=r;i++) a[i]=tmp[i];
} int main(){
// freopen("5.in","r",stdin);
scanf("%d %lf",&n,&S);
for(int i=1;i<=n;i++){
scanf("%lf %lf %lf",&A[i],&B[i],&R[i]);
}
dp[0]=S;
for(int i=0;i<=n;i++){
a[i].id=i;
}
sort(a,a+1+n,cmp1);
cdq_divide(0,n);
printf("%.3lf\n",dp[n]);
}

[BZOJ1492] [NOI2007] 货币兑换Cash(cdq分治+斜率优化)的更多相关文章

  1. bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

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

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

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

  3. BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)

    BZOJ1492:[NOI2007]货币兑换 题目传送门 [问题描述] 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券).每个持有金券的 ...

  4. BZOJ1492: [NOI2007]货币兑换Cash(CDQ分治,斜率优化动态规划)

    Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...

  5. bzoj 1492: [NOI2007]货币兑换Cash【贪心+斜率优化dp+cdq】

    参考:http://www.cnblogs.com/lidaxin/p/5240220.html 虽然splay会方便很多,但是懒得写,于是写了cdq 首先要想到贪心的思路,因为如果在某天买入是能得到 ...

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

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

  7. 【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

    题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n ...

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

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

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

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

随机推荐

  1. java.sql.SQLException: Unknown system variable 'query_cache_size'

    改为 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java< ...

  2. 原生js禁止页面滚动

    // 开启.禁止页面滚动 bodyScroll: { e(e) { e.preventDefault();// 注意此处代码片段必须这样提出来已保证传入下边两个事件的处理程序一样才生效,分别写到事件处 ...

  3. java -cp与java -jar的区别

    java -cp 和 -classpath 一样,是指定类运行所依赖其他类的路径,通常是类库,jar包之类,需要全路径到jar包,window上分号“;”格式:java -cp .;myClass.j ...

  4. day02记

    一.Tomcat搭建 1.service和controller分别搭建独立的Tomcat且port不一致 2.部署项目选择带有exploded的 3.运行时应先启动service再启动controll ...

  5. Node.js 版本管理工具——nvm

    日常项目开发中,有些项目可能基于node  V10 或者 V8 不同的版本: 如果我们手动安装卸载node,这样是不友好. 先放上作者的博客地址 : https://www.cnblogs.com/g ...

  6. Go简易分布式对象存储 合并文件的所有分块为一个文件

    项目 项目地址: https://github.com/Draymonders/cloud 欢迎大家Watch or Star 缘由 由于项目中对大文件进行5MB为一个分块上传(多线程,提升上传效率) ...

  7. flex兼容问题

    display:flex作为C3的新属性,还是有的浏览器不支持的,那下面我们就来说一下他的兼容写法 .box{ display: -webkit-box; /* 老版本语法: Safari, iOS, ...

  8. 版本基线自动化之windows

    1.背景: 目前项目维护周期过程中,制作调试版本和对外发布版本次数比较频繁,流程过于繁琐和随意,且打包制作人成为瓶颈,为了规范版本基线流程和实现全员自动化参与,拟定版本基线自动化方案. 2.目标: 版 ...

  9. 全球DC主机交流

    全球DC主机交流https://www.globaldc.cn/ 全球DC主机交流论坛是一个综合性的国内服务器.国外服务器.高防清洗.硬件服务器交流论坛,主要为网友提供IP地址鉴定主机商,全球独立服务 ...

  10. Java heap size

    今天在性能诊断工作中遇到 Java heap size, 下面是它的相关的概念. 什么是Java heap size ? Java heap size 堆栈大小, 指Java 虚拟机的内存大小.我的理 ...