BZOJ

洛谷

如果某天能够赚钱,那么一定会在这天把手上的金券全卖掉。同样如果某天要买,一定会把所有钱花光。

那么令\(f_i\)表示到第\(i\)天所拥有的最多钱数(此时手上没有任何金券),可以选择什么都不干,\(f_i=f_{i-1}\);也可以从之前的某一天\(j\)花\(f_j\)的钱买金券,在第\(i\)天全卖掉。用第\(j\)天的信息算一下买了多少\(A,B\),就可以得到第\(i\)天卖了多少钱。

所以有\(f_i=\max\{f_{i-1},\ A_i\frac{f_jk_j}{A_jk_j+B_j}+B_i\frac{f_j}{A_jk_j+B_j}\}\)。

把后面那部分写成直线的形式:\(\frac{f_i}{B_i}-\frac{A_i}{B_i}*\frac{f_jk_j}{A_jk_j+B_j}=\frac{f_j}{A_jk_j+B_j}\),令\(x_j=\frac{f_jk_j}{A_jk_j+B_j},\ y_j=\frac{f_j}{A_jk_j+B_j}\),\(\frac{f_i}{B_i}-\frac{A_i}{B_i}x_j=y_j\)。要求用\(k=-\frac{A_i}{B_i}\)的直线去切\((x_j,y_j)\)使得截距最大,也就是维护上凸壳。

但\(x\)即每个决策点不是单调的,就需要平衡树/CDQ分治去维护凸包。

CDQ分治:

先将所有点按斜率\(k\)排序。

先处理完左区间询问,然后将左区间按横坐标\(x\)归并排好序。这样处理右区间询问的时候(现在只考虑当前左区间对整个右区间询问的影响,也就是要对左区间维护上凸壳),左区间的\(x\)有序就可以直接用单调栈把上凸壳维护出来了。

而右区间已经按斜率\(k\)排好序了,所以可以\(O(n)\)在上凸壳中得到最优解(实现当前整个左区间对右区间的转移)。

当递归到\(l=r\),就说明已经处理完该点\(l\)之前的点对\(l\)的影响了,就可以直接得到\(f_l\)的值(顺便要和\(f_{l-1}\)取\(\max\))并更新\(l\)这个决策点的信息了。

平衡树:

节点按\(x\)排序。每个节点维护与左边点和右边点的斜率\(lk,rk\)。(树上的节点都是凸包上的,凸包内部的就不要了)

对于新的决策点\(x\),直接先插入到平衡树中。

然后将\(x\)转到根。先找左边第一个能与\(x\)构成凸包的点:若当前点\(y\)与前一个点的斜率\(lk\gt k(x,y)\),那么如果\(y\)右边还有在凸包上的点,就继续向右找(没有就结束)。否则若\(lk\lt k(x,y)\),则应继续往左找。

找右边第一个能与\(x\)构成凸包的点同理。

最后,如果\(x\)就在凸包里面,即\(lk(x)<rk(x)\),就要把\(x\)从平衡树中删掉。

查询就根据斜率直接查询最优决策点了。

复杂度都是\(O(n\log n)\)。


CDQ分治:

//12648kb	792ms
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define eps 1e-9
typedef long long LL;
const int N=1e5+5;
const double INF=1e17; double f[N],read();
char IN[MAXIN],*SS=IN,*TT=IN;
struct Node
{
int id;
double A,B,k,Rate,x,y;
inline void Init(int i)
{
id=i,A=read(),B=read(),k=-A/B,Rate=read();
}
bool operator <(const Node &x)const
{
return k<x.k;
}
}q[N]; inline double read()
{
double x=0,y=0.1;register char c=gc();
for(;!isdigit(c)&&c!='.';c=gc());
for(;isdigit(c);x=x*10+c-'0',c=gc());
for(c=='.'&&(c=gc());isdigit(c);x+=(c-'0')*y,y*=0.1,c=gc());
return x;
}
inline double GetK(int i,int j)
{
return fabs(q[i].x-q[j].x)<=eps?(q[i].y<q[j].y?-INF:INF):(q[i].y-q[j].y)/(q[i].x-q[j].x);
// return fabs(q[i].x-q[j].x)<=eps?INF:(q[i].y-q[j].y)/(q[i].x-q[j].x);
}
void CDQ(int l,int r)
{
static int sk[N];
static Node tmp[N];
if(l==r)
{
f[l]=std::max(f[l],f[l-1]);
q[l].y=f[l]/(q[l].A*q[l].Rate+q[l].B), q[l].x=q[l].y*q[l].Rate;
return;
}
int mid=l+r>>1,p1=l,p2=mid+1;
for(int i=l; i<=r; ++i)//将前mid个询问放在左边 后mid个放在右边
q[i].id<=mid?tmp[p1++]=q[i]:tmp[p2++]=q[i];
for(int i=l; i<=r; ++i) q[i]=tmp[i];
CDQ(l,mid); int top=0;
for(int i=l; i<=mid; ++i)
{
while(top>=2 && GetK(i,sk[top])>GetK(sk[top],sk[top-1])) --top;
sk[++top]=i;
}
for(int i=mid+1; i<=r; ++i)
{
while(top>=2 && GetK(sk[top],sk[top-1])<q[i].k) --top;
int j=sk[top];
f[q[i].id]=std::max(f[q[i].id],q[i].A*q[j].x+q[i].B*q[j].y);
}
CDQ(mid+1,r); p1=l,p2=mid+1; int p=l;//处理完整个区间后按x排序
while(p1<=mid && p2<=r) q[p1].x<=q[p2].x?tmp[p++]=q[p1++]:tmp[p++]=q[p2++];
while(p1<=mid) tmp[p++]=q[p1++];
while(p2<=r) tmp[p++]=q[p2++];
for(int i=l; i<=r; ++i) q[i]=tmp[i];
} int main()
{
int n=read(); f[0]=read();
for(int i=1; i<=n; ++i) q[i].Init(i);
std::sort(q+1,q+1+n), CDQ(1,n);
printf("%.3lf\n",f[n]); return 0;
}

Splay:(快好多啊)

//6196kb	340ms
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define eps 1e-9
typedef long long LL;
const int N=1e5+5;
const double INF=1ll<<60; double f[N],X[N],Y[N];
char IN[MAXIN],*SS=IN,*TT=IN; inline double read()
{
double x=0,y=0.1;register char c=gc();
for(;!isdigit(c)&&c!='.';c=gc());
for(;isdigit(c);x=x*10+c-'0',c=gc());
for(c=='.'&&(c=gc());isdigit(c);x+=(c-'0')*y,y*=0.1,c=gc());
return x;
}
inline double GetK(int i,int j)
{
return fabs(X[i]-X[j])<eps?INF:(Y[i]-Y[j])/(X[i]-X[j]);
}
struct SPLAY
{
#define ls son[x][0]
#define rs son[x][1]
int root,tot,fa[N],son[N][2];
double lk[N],rk[N]; void Rotate(int x,int &k)
{
int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
if(a==k) k=x;
else son[b][son[b][1]==a]=x;
fa[a]=x, fa[x]=b, fa[son[x][r]]=a, son[a][l]=son[x][r], son[x][r]=a;
}
void Splay(int x,int &k)
{
while(x!=k)
{
int a=fa[x];
if(a!=k) son[a][1]==x^son[fa[a]][1]==a?Rotate(x,k):Rotate(a,k);
Rotate(x,k);
}
}
int Find(double k)
{
int x=root;
while(x)
{
if(lk[x]>=k && rk[x]<=k) return x;
if(lk[x]<k) x=son[x][0];
else x=son[x][1];
}
return x;
}
int Pre(int x)
{
int y=son[x][0],res=y;
while(y)
{
if(lk[y]>=GetK(x,y)) res=y, y=son[y][1];
else y=son[y][0];
}
return res;
}
int Nxt(int x)
{
int y=son[x][1],res=y;
while(y)
{
if(rk[y]<=GetK(x,y)) res=y, y=son[y][0];
else y=son[y][1];
}
return res;
}
void Insert(int x,double xx)
{
int f=0,p=x; x=root;
while(x) f=x, x=son[x][xx>X[x]];
x=p, fa[x]=f, son[f][xx>X[f]]=x;
Splay(x,root);
}
void Maintain(int x)
{
if(ls)
{
int y=Pre(x);
Splay(y,ls), son[y][1]=0;
lk[x]=rk[y]=GetK(x,y);
}
else lk[x]=INF;
if(rs)
{
int y=Nxt(x);
Splay(y,rs), son[y][0]=0;
rk[x]=lk[y]=GetK(x,y);
}
else rk[x]=-INF;
if(lk[x]<=rk[x])
{
int y=rs;
fa[root=ls]=0, son[root][1]=y, fa[y]=root;
rk[root]=lk[y]=GetK(root,y);
}
}
}T; int main()
{
int n=read(); f[0]=read();
for(int i=1; i<=n; ++i)
{
double A=read(),B=read(),Rate=read();
int j=T.Find(-A/B);
f[i]=std::max(f[i-1],A*X[j]+B*Y[j]);
Y[i]=f[i]/(A*Rate+B), X[i]=Y[i]*Rate;
T.Insert(i,X[i]), T.Maintain(i);
}
printf("%.3lf\n",f[n]); return 0;
}

BZOJ.1492.[NOI2007]货币兑换(DP 斜率优化 CDQ分治/Splay)的更多相关文章

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

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

  2. 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)

    题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...

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

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

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

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

  5. 【BZOJ-1492】货币兑换Cash DP + 斜率优化 + CDQ分治

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

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

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

  7. [NOI2007]货币兑换 --- DP + 斜率优化(CDQ分治)

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

  8. 洛谷.4655.[CEOI2017]Building Bridges(DP 斜率优化 CDQ分治)

    LOJ 洛谷 \(f_i=s_{i-1}+h_i^2+\min\{f_j-s_j+h_j^2-2h_i2h_j\}\),显然可以斜率优化. \(f_i-s_{i-1}-h_i^2+2h_ih_j=f_ ...

  9. BZOJ_3963_[WF2011]MachineWorks_斜率优化+CDQ分治

    BZOJ_3963_[WF2011]MachineWorks_斜率优化+CDQ分治 Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM) ...

随机推荐

  1. jacoco + eclipse单元测试覆盖率

    概念 Jacoco:JaCoCo是一个开源的覆盖率工具,它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant.Maven中:可以作为Eclipse插件,可以使用其JavaAgent技术监控J ...

  2. eclipse的安装及使用

    1.安装 2工作区 3透视图添加透视图 关闭和显示各个子视图 点击视图右上角的关闭按钮可以关闭当前视图 可以选择Window-->Show View菜单项打开各个子视图 4创建项目 选择File ...

  3. jenkins+git+maven 增量部署思路以及相关脚本

    之前通过jenkins+Git+maven这种方式打war包然后scp到测试环境使用,但是现在项目组要求打增量包,即只部署修改的文件和配置文件. 核心问题:如何获取到变动的文件??? 前置条件:初始化 ...

  4. error: each element of 'ext_modules' option must be an Extension instance or 2-tuple

    在编译cython扩展时出现. 解决办法: 必须先import setup再import extension,否则报错 from setuptools import setup from distut ...

  5. Vim设计

    像 IDE 一样使用 vim 免费的编程中文书籍索引

  6. Select2 多层次赋值时异步赋值的问题

    场景: 当选择人员时加载人员,选择部门时加载部门.所以在人员下,选择人员A后,如果选择部门,会触发二级select 重新获取数据. 问题: 使用select2()方法进行绑定远程数据后,对第二个sel ...

  7. Spring boot+CXF开发WebService Demo

    最近工作中需要用到webservice,而且结合spring boot进行开发,参照了一些网上的资料,配置过程中出现的了一些问题,于是写了这篇博客,记录一下我这次spring boot+cxf开发的w ...

  8. vscode插件篇

    Document This 注释插件 能够自动识别function中的参数 Ctrl + alt + D

  9. [转]解决-Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HOME environment variable and mvn script match.

    来源:http://www.cnblogs.com/sprinng/p/5141233.html 1.添加M2_HOME的环境变量 2.Preference->Java->Installe ...

  10. Windows下Mongodb启动问题

    把mongodb安装完,运行server出现问题