先说一下斜率优化:这是一种经典的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. python学习之路2(程序的控制结构)

    1.程序的分支结构 1.1 单分支 if <条件>:                       例:guess = eval(input()) <语句块>          ...

  2. Tensorflow 笔记:第一讲

    一. 基本概念 1. 什么是人工智能 人工智能的概念: 机器模拟人的意识和思维 重要人物: 艾伦·麦席森·图灵( Alan Mathison Turing) 人物简介: 1912 年 6 月 23 日 ...

  3. python网络编程的坑(持续更新)

    初学python,踩了许多坑...每天都学一点吧..(大佬绕过) 1.session的用法: session是python requests库中的一个重要功能.session可以存储用户的数据并且存储 ...

  4. 博弈dp 以I Love this Game! POJ - 1678 为例

    写在前面的话 知识基础:一些基础的博弈论的方法,动态规划的一些知识 前言:博弈论就是一些关于策略或者游戏之间的最优解,动态规划就是对于一些状态之间转移的一些递推式(or 递归),dp分为很多很多种,比 ...

  5. 003---设计首页index页面

    在项目的urls.py文件添加一条url from django.contrib import admin from django.urls import path, re_path from app ...

  6. PHP.40-TP框架商城应用实例-后台15-商品属性与库存量1-不同商品(唯一属性、可选属性),属性类型

    思路: 1.不同商品属于不同的类型,如:手机.服装.电脑等类型 2.不同的类型有不同的属性,其中分为唯一属性和可选属性,如服装:可选属性{尺寸:S,M,L……;颜色:白色,黑色……}唯一属性:材质 首 ...

  7. P1331 海战

    P1331 海战 题目描述 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物,领空将布满了F-2003飞机.此外,巡洋船只和舰队将被派去保护海岸线.不幸的是因为种种原因,国防 ...

  8. leetcode笔记--2 reverse string

    my answer: 出错点:new_list[s] = list_s[u-1-s] 这样会出错, 重点:(1) map(str, s) 函数的使用,例:ls = [1,2,3]rs = map(st ...

  9. Flask 中文手册 0.10 文档

    Flask 中文手册 0.10 文档 欢迎使用 Flask 欢迎阅读 Flask 文档. 本文档分为几个部分.我推荐您先从 安装 开始,之后再浏览 快速入门 章节. 教程 比快速入门更详细地介绍了如何 ...

  10. 自动化测试-selenium启动浏览器

    在自动化测试过程中,通过selenium启动浏览器时,可能需要加载插件(如测试用的firebug.或产品中要求必须添加某插件等).读取用户数据(自己浏览器的配置文件/别人直接给的浏览器配置文件).设置 ...