先说一下斜率优化:这是一种经典的dp优化,是OI中利用数形结合的思想解决问题的典范,通常用于优化dp,有时候其他的一些决策优化也会用到,看待他的角度一般有两种,但均将决策看为二维坐标系上的点,并转化为维护凸壳,一种根据两点的斜率与某一常数的大小关系推断二者的优劣,一种将转移方程化为相关直线方程,通过取得最大(小)截距来求最优解。关于其实现方法上,当点的x坐标单调时,可依据比较常数是否单调选择单调队列或单调栈,而当其x坐标不单调时常常使用CDQ分治或平衡树来实现。

  千万别用替罪羊来写动态凸壳!!!

  用平衡树来写动态凸壳的话,很容易想到的是维护凸壳点集并使x坐标单调,那么这个时候你不仅得到了单调的x坐标,点与点之间的斜率也就是单调的了,这个时候你就可以给每个点再维护两个值:他与他在凸壳上左边的点连成的线段的斜率和他与他在凸壳上右边的点连成的线段的斜率(边界设为正无穷和负无穷),维护了这两个值你就可以直接在二叉树上查找最优决策点,而不用二分。当插入一个点的时候,你可以在这个点两边暴力pop,这样均摊nlogn,也可以直接在这个点两边进行二叉查找这样严格nlogn,但是常数相对较小。用splay或者Treap(无旋有旋都可以,只是常数差异)会很优秀,但是用替罪羊的话,呵呵.......不仅码量爆炸,而且各种操作都不是很好实现,就拿维护上面说的两个值来讲,如果你的替罪羊删除用的是标记,那么你就要**了.....因为废点在二叉查找的时候也需要有指示作用,但是你不能把他放入凸壳来维护,所以你还要维护一下盖住他的线段的斜率......(可能写替罪羊的时候把维护的信息统一改为前驱实点和后继实点会好很多)

  下面是巨丑巨慢的替罪羊程序.....

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ft first
#define sd second
#define mmp(a,b) (std::make_pair(a,b))
#define get_k(x,y) (((x)->b-(y)->b)/((x)->a-(y)->a))
typedef double db;
typedef std::pair<db,db> pdd;
const int N=;
const db eps=1e-;
const db Inf=./.;
const db oo=-./.;
db A[N],B[N],R[N],f[N];
int n,s;
namespace SGT{
const db alpha=0.75;
struct ScapeGoat_Tree{
ScapeGoat_Tree *ch[],*zz;
int size,cover,ex;
db a,b,lk,rk;
inline void pushup(){
size=ch[]->size+ch[]->size+ex;
cover=ch[]->cover+ch[]->cover+;
}
inline void update();
inline bool isbad(){
return cover*alpha+<ch[]->cover||cover*alpha+<ch[]->cover;
}
}*root,*null,node[N],*list[N];
int len,sz;
inline void ScapeGoat_Tree:: update(){
if(ch[]->zz!=null)return void(zz=ch[]->zz);
if(ex)return void(zz=this);
zz=ch[]->zz;
}
inline void Init(){
null=node+(sz++);
null->ch[]=null->ch[]=null->zz=null;
root=null;
}
inline void travel(ScapeGoat_Tree *p){
if(p==null)return;
travel(p->ch[]);
if(p->ex)list[++len]=p;
travel(p->ch[]);
}
inline ScapeGoat_Tree *divide(int l,int r){
if(l>r)return null;
int mid=(l+r)>>;
list[mid]->ch[]=divide(l,mid-);
list[mid]->ch[]=divide(mid+,r);
list[mid]->pushup();
list[mid]->update();
return list[mid];
}
inline void rebuild(ScapeGoat_Tree *&p){
len=,travel(p),p=divide(,len);
}
inline int get_rank(db x){
int ret=;
ScapeGoat_Tree *p=root;
while(p!=null)
if(p->a<x+eps)
ret+=p->ch[]->size+p->ex,p=p->ch[];
else
p=p->ch[];
return ret;
}
inline ScapeGoat_Tree *get_kth(int k){
ScapeGoat_Tree *p=root;
while(true)
if(p->ex&&p->ch[]->size+p->ex==k)
return p;
else if(p->ch[]->size>=k)
p=p->ch[];
else k-=p->ch[]->size+p->ex,p=p->ch[];
}
inline ScapeGoat_Tree **insert(ScapeGoat_Tree *&p,db x,db y){
if(p==null){
p=node+(sz++);
p->ch[]=p->ch[]=null;
p->size=p->cover=p->ex=;
p->a=x,p->b=y,p->zz=p;
return &null;
}
++p->size,++p->cover;
ScapeGoat_Tree **ret=insert(p->ch[p->a<x],x,y);
if(p->isbad())ret=&p;
p->update();
return ret;
}
inline void Insert(db x,db y){
int k=get_rank(x);
ScapeGoat_Tree *p1,*p2,*p3;
ScapeGoat_Tree **p=insert(root,x,y);
p2=node+(sz-);
if(k!=){
p1=get_kth(k);
p1->rk=p2->lk=get_k(p1,p2);
}else
p2->lk=Inf;
if(k+<=root->size){
p3=get_kth(k+);
p2->rk=p3->lk=get_k(p2,p3);
}else
p2->rk=oo;
if(*p!=null)rebuild(*p);
}
inline void del(ScapeGoat_Tree *p,int k){
--p->size;
if(p->ex&&p->ch[]->size+p->ex==k){
p->ex=,p->update();
return;
}
if(p->ch[]->size>=k)del(p->ch[],k);
else del(p->ch[],k-p->ch[]->size-p->ex);
p->update();
}
inline void Del(ScapeGoat_Tree *p){
int k=get_rank(p->a);
del(root,k);
ScapeGoat_Tree *p1,*p2;
if(root->size!=){
if(k==){
p2=get_kth(k);
p2->lk=Inf;
}else if(k>root->size){
p1=get_kth(k-);
p1->rk=oo;
}else{
p2=get_kth(k);
p1=get_kth(k-);
p1->rk=p2->lk=get_k(p1,p2);
}
}
if(root->size+<root->cover*alpha)rebuild(root);
}
inline void Del(int k){
del(root,k);
ScapeGoat_Tree *p1,*p2;
if(root->size!=){
if(k==){
p2=get_kth(k);
p2->lk=Inf;
}else if(k>root->size){
p1=get_kth(k-);
p1->rk=oo;
}else{
p2=get_kth(k);
p1=get_kth(k-);
p1->rk=p2->lk=get_k(p1,p2);
}
}
if(root->size+<root->cover*alpha)rebuild(root);
}
inline bool die(int k){
ScapeGoat_Tree *p=get_kth(k);
return p->lk<p->rk+eps;
}
inline void Ins(db x,db y){
int k=get_rank(x);
if(k==){
Insert(x,y),++k;
}else{
ScapeGoat_Tree *p=get_kth(k);
if(fabs(p->a-x)<eps)
p->b=std::max(p->b,y);
else
Insert(x,y),++k;
}
if(die(k))return void(Del(k));
while(k!=root->size&&die(k+))Del(k+);
while(k!=&&die(k-))Del(k-),--k;
}
inline pdd query(ScapeGoat_Tree *p,db k){
if(p->ex&&k<=p->lk+eps&&eps+k>=p->rk)
return mmp(p->a,p->b);
if((p->ex&&k>p->lk+eps)||(p->ex==&&(p->ch[]->size==||p->ch[]->zz->lk<k)))
return query(p->ch[],k);
else
return query(p->ch[],k);
}
}
int main(){
scanf("%d%d",&n,&s);
int i;SGT::Init();
for(i=;i<=n;++i)
scanf("%lf%lf%lf",&A[i],&B[i],&R[i]);
f[]=s;
db y=s/(R[]*A[]+B[]),x=y*R[];
SGT::Insert(x,y);
pdd ret;
for(i=;i<=n;++i){
ret=SGT::query(SGT::root,-A[i]/B[i]);
f[i]=B[i]*ret.sd+A[i]*ret.ft;
f[i]=std::max(f[i],f[i-]);
y=f[i]/(R[i]*A[i]+B[i]),x=y*R[i];
SGT::Ins(x,y);
}
printf("%.3f",f[n]);
return ;
}

【BZOJ 1492】 [NOI2007]货币兑换Cash 斜率优化DP的更多相关文章

  1. BZOJ 1492: [NOI2007]货币兑换Cash 斜率优化 + splay动态维护凸包

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

  2. 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的数量. 然后就很明显了...平衡 ...

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

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

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

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

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

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

  6. ●BZOJ 1492 [NOI2007]货币兑换Cash

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1492 题解: 斜率优化DP,CDQ分治 定义$DP[i]$为第i天结束后的最大收益. 由于题 ...

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

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

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

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

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

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

随机推荐

  1. stm32+lwip(四):网页服务器测试

    我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...

  2. x86的控制寄存器CR0,CR1,CR2,CR3

    状态和控制寄存器组除了EFLAGS.EIP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3. 这几个寄存器中保存全局性和任务无关的机器状态. CR0中包含了6个预定义标志,0位是保 ...

  3. P2340 奶牛会展(状压dp)

    P2340 奶牛会展 题目背景 奶牛想证明它们是聪明而风趣的.为此,贝西筹备了一个奶牛博览会,她已经对N 头奶牛进行 了面试,确定了每头奶牛的智商和情商. 题目描述 贝西有权选择让哪些奶牛参加展览.由 ...

  4. Mysql自学笔记

    SQL(strucut query language) DDL (数据库定义语言)DML (数据库操作语言)DCL (数据库的控制语言)DTL (数据库的高级语言)查看版本的函数select vers ...

  5. Python网络编程(socketserver、TFTP云盘、HTTPServer服务器模型)

    HTTP协议? HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型.HTTP是一个无状态的协议. 通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了 ...

  6. 梳理 Opengl ES 3.0 (二)剖析一个GLSL程序

    OpenGL ES shading language 3.0 也被称作 GLSL,是个 C风格的编程语言. Opengl ES 3.0内部有两种可编程处理单元,即Vertex processor和Fr ...

  7. 在阿里云上遇见更好的Oracle(三)

    鬼扯完“去IOE”,继续回来说说这个系列文章的主角Oracle. 在DB-Engine的数据库排行榜中,Oracle已经占据了多年的第一(最新排名可以点击“阅读原文”).当然因为互联网行业的兴起,My ...

  8. 配置SSH无密钥登陆(三)

    配置SSH无密钥登陆 (1).关闭防火墙 对每个虚拟机进行如下操作:   su    chkconfig  iptables  off 执行之后重启虚拟机:reboot (2).关闭之后,在maste ...

  9. truffle开发一个简单的Dapp

    1.安装Truffle:npm install -g truffle 2.建立项目目录并进入:mkdir pet-shop-tutorial cd pet-shop-tutorial 3.使用truf ...

  10. MySQL 初识01

    最近开始学习MySQL 所以将这两天所学习到的知识简单小结一下 1.status 显示数据库信息 2.数据类型: a.字符串: char(m):固定长度的字符,最多255个字符: varchar(m) ...