先说一下斜率优化:这是一种经典的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. ant + jmeter 自动化接口测试环境部署

    1.jdk下载安装 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.jmeter下载 jmeter官 ...

  2. grep用法小结

    用法 grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] -e PATTERN ... [FILE...] grep [OPTIONS] -f FILE . ...

  3. sort函数

    做项目的时候,排序是一种经常要用到的操作.如果每次都自己写个冒泡之类的O(n^2)排序,不但程序容易超时,而且浪费宝贵的时间,还很有可能写错.STL里面有个sort函数,可以直接对数组排序,复杂度为n ...

  4. intellij idea之git执行打标签(tag)和删除标签

    intellij idea 版本为2017.2.6 进入Version Control-->log 1.在之前版本中,右键,新建标签 2.输入标签名称,建议输入版本号的方式 3.push标签 由 ...

  5. How to add a webpart to your website

          I have download a webpart that can play media on the website from the internet.Then how to add ...

  6. How to enable download EXE files from the Sharepoint website

          As we all know,many applications have forbidden to upload and download exe files.Because the e ...

  7. [网站日志]今天早上遭遇的CPU 100%情况

    今天早上9:06左右,Windows性能监视器监测到主站的Web服务器出现了CPU 100%的情况,伴随着Requests/Sec的上升,详见下图. 上图中红色线条表示的是%Processor Tim ...

  8. 《剑指offer》题解

    有段时间准备找工作,囫囵吞枣地做了<剑指offer>提供的编程习题,下面是题解收集. 当初没写目录真是个坏习惯(-_-)||,自己写的东西都要到处找. 提交的源码可以在此repo中找到:h ...

  9. 「Haskell 学习」一 环境与大致了解

    感谢<Real World Haskell>在网上的免费发布,可以白嫖学Haskell这个久闻大名的函数式编程语言了. 本文运行于openSUSE Tumbleweed下,运行相关命令时留 ...

  10. Vue一些重要的知识点

    vue sync修饰(1)双向数据绑定,父子组件之间信息的交互 1⃣️在自组件中使用this.emmit('toFather'),子组件产生一个tofather事件,然后在父组件中通过@进行监听,那么 ...