Description

你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器。原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器。你的任务是在转型期内尽可能得到更大的收益。在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润。因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器。
在转型期内,有若干台可能卖出的机器。作为先进机器的专家,对于每台机器Mi,你已经知道了其价格Pi和可以买入的日期Di。注意,如果不在第Di天买入机器Mi,那么别的人也会买走这一台机器,也就是说,以后你将没有机会购买这台机器了。如果ACM的钱低于一台机器的价格,那么你显然不可能买到这一台机器。
如果你在第Di天买入了机器Mi,那么ACM公司可以从第(Di)+1天开始使用这一台机器。每使用这台机器一天,就可以为公司创造出Gi美元的收益。
你可以决定要在买入之后的某一天,以一定的折扣价卖出这一台机器。收购市场对于每一台机器,都有一个折扣价Ri。你不能在卖出的那一天使用机器,但是你可以在卖出的那一天再买入一台新的。
在转型期结束后,ACM公司会卖掉当前所拥有的机器。你的任务就是最大化转型期间ACM公司可以得到的收入。

Input

输入包含若干组测试用例。每一组测试用例的第一行有3个正整数N,C和D。N是将会卖出的机器的台数(N<=10^5),C是在转型期开始时公司拥有的美元数量(C<=10^9),D是转型期持续的天数(D<=10^9)。
之后的N行每一行描述了一台机器的情况。每一行有4个正整数Di,Pi,Ri和Gi,分别表示这台机器卖出的时间,购买这台机器需要的美元数量,卖出这台机器的折扣价和使用这台机器可以得到的利润。这些数字满足1<=Di<=D,1<=Ri<Pi<=10^9且1<=Gi<=10^9.
最后一组测试用例后面的一行由3个0组成,表示输入数据。

Output

对于每一组测试用例,输出测试用例的编号,之后给出ACM公司在第D+1天结束后可以得到的最大数量的美元。
请依照下面给出的样例输出。
 
 题解:令 $f_{i}$ 表示 $1$ ~ $i$ 的最大收入
则 $f_{i}=f_{j}-P_{j}+R_{j}+G_{j}\times(D_{i}-D{j}-1)$
化成一次函数形式:
$-D_{i}\times G_{j}+F_{i}=f_{j}-P_{j}+R_{j}-G_{j}D_{j}-G_{j}$
$x=G_{j}$,$y=f_{j}-P_{j}+R_{j}-G_{j}D_{j}-G_{j}$,$slope=-D_{j}$
可以用斜率优化来求解.
然而,$x$ 并不单调,所以要用平衡树来动态维护这个凸包
我选择了 $splay$
一定要特别注意横坐标相等的情况,一定特判是无限大还是无限小
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 300000
#define inf 10000000000000009
#define ll long long
using namespace std;
const long double eps = 1e-10;
int root;
int idxx[maxn];
struct Splaytree
{
#define get(x) (ch[f[x]][1]==x)
int cnt;
int ch[maxn][2],f[maxn];
long double X[maxn],Y[maxn],lk[maxn],rk[maxn];
// i 在前, j 在后
long double slope(int i,int j)
{
if(fabs(X[i]-X[j])<=eps) return Y[j]>Y[i] ? (long double)inf : (long double)-inf;
return (Y[i]-Y[j])/(X[i]-X[j]);
}
inline void rotate(int x)
{
int old=f[x],fold=f[old],which=get(x);
ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
ch[x][which^1]=old,f[old]=x,f[x]=fold;
if(fold) ch[fold][ch[fold][1]==old]=x;
}
inline void splay(int x,int &tar)
{
int fa,u=f[tar];
for(;(fa=f[x])!=u;rotate(x))
if(f[fa]!=u)
rotate(get(fa)==get(x)?fa:x);
tar=x;
}
inline int getl(int x)
{
while(ch[x][0]) x=ch[x][0];
return x;
}
inline int getr(int x)
{
while(ch[x][1]) x=ch[x][1];
return x;
}
inline void insert(int &o,double x,double y,int last)
{
if(!o)
{
o=++cnt;
f[o]=last, X[o]=x,Y[o]=y;
return;
}
insert(ch[o][x-X[o]>eps], x, y, o);
}
inline int getans(int x,double k)
{
if(!x) return 0;
if(k<=lk[x]+eps&&k+eps>=rk[x]) return x;
if(lk[x]<k+eps) return getans(ch[x][0], k);
else return getans(ch[x][1], k);
}
inline void del(int x)
{
if(!ch[x][0])
{
int right=getl(ch[x][1]);
splay(right,ch[x][1]), root=right, f[root]=ch[x][1]=0;
lk[root]=inf; }
else if(!ch[x][1])
{
int left=getr(ch[x][0]);
splay(left,ch[x][0]), root=left, f[root]=ch[x][0]=0;
rk[root]=-inf;
}
else
{
int left=getr(ch[x][0]),right=getl(ch[x][1]);
splay(left,ch[x][0]), splay(right,ch[x][1]);
root=left, f[root]=0, ch[root][1]=right, f[right]=root;
rk[root]=lk[right]=slope(root,right);
}
}
// 平衡树上查询前驱
inline int pre(int x)
{
int cur=ch[x][0],re=0;
while(cur)
{
if(slope(cur,x)+eps>=rk[cur]) re=cur,cur=ch[cur][0];
else cur=ch[cur][1];
}
return re;
}
// 平衡树上查询后继
inline int nxt(int x)
{
int cur=ch[x][1],re=0;
while(cur)
{
if(slope(x,cur)<=lk[cur]+eps) re=cur,cur=ch[cur][1];
else cur=ch[cur][0];
}
return re;
}
inline void maintain(int x)
{
splay(x,root);
if(ch[root][0])
{
int left=pre(root);
if(left)
{
splay(left, ch[x][0]);
ch[left][1]=f[ch[left][1]]=0;
rk[left]=lk[x]=slope(left, x);
}
else lk[x]=-inf;
}
else lk[x]=inf;
if(ch[x][1])
{
int right=nxt(x);
if(right)
{
splay(right, ch[x][1]);
ch[right][0]=f[ch[right][0]]=0;
rk[x]=lk[right]=slope(x, right);
}
else rk[x]=inf;
}
else rk[x]=-inf;
if(lk[x]-rk[x]<=eps) del(x);
}
}splay;
int n;
ll d;
struct Node
{
ll P,D,G,R;
}t[maxn];
ll F[maxn];
bool cmp(Node i,Node j) { return i.D<j.D; }
inline void work()
{
root=splay.cnt=0;
int i,j=0;
for(i=1;i<=n;++i) scanf("%lld%lld%lld%lld",&t[i].D,&t[i].P,&t[i].R,&t[i].G);
t[++n].D=d+1;
t[n].P=t[n].R=t[n].G=0;
sort(t+1,t+1+n,cmp);
ll ret=F[0], re=0;
for(i=1;i<=n;++i)
{
F[i]=F[i-1];
if(root)
{
j=splay.getans(root, (long double)-1.00000*t[i].D);
j=idxx[j];
re=F[j]-t[j].P+t[j].R+t[j].G*(t[i].D-t[j].D-1LL);
F[i]=max(F[i-1],re);
}
ret=max(ret,F[i]);
if(i!=n&&F[i]>=t[i].P)
{
splay.insert(root, (long double)t[i].G, (long double)(F[i]-t[i].P+t[i].R-t[i].G*(t[i].D+1LL)),0);
idxx[splay.cnt]=i;
splay.maintain(splay.cnt);
}
}
printf("%lld\n",ret);
for(int i=0;i<=splay.cnt;++i) splay.ch[i][0]=splay.ch[i][1]=splay.f[i]=splay.lk[i]=splay.rk[i]=0;
root=splay.cnt=0;
}
int main()
{
for(int cas=1;;++cas)
{
scanf("%d%lld%lld",&n,&F[0],&d);
if(n==0&&F[0]==0&&d==0) break;
printf("Case %d: ",cas);
work();
}
return 0;
}

  

BZOJ 3963: [WF2011]MachineWorks 斜率优化 + splay动态维护凸包的更多相关文章

  1. HDU 3824/ BZOJ 3963 [WF2011]MachineWorks (斜率优化DP+CDQ分治维护凸包)

    题面 BZOJ传送门(中文题面但是权限题) HDU传送门(英文题面) 分析 定义f[i]f[i]f[i]表示在iii时间(离散化之后)卖出手上的机器的最大收益.转移方程式比较好写f[i]=max{f[ ...

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

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

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

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

  4. ●BZOJ 3963 [WF2011]MachineWorks

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3963 题解: 斜率优化DP,CDQ分治. 先按时间排序.(规定以下内容的第i台机器的卖出时间 ...

  5. BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

    传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以 ...

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

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

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

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

  8. BZOJ 1767] [Ceoi2009] harbingers (斜率优化)

    [BZOJ 1767] [Ceoi2009] harbingers (斜率优化) 题面 给定一颗树,树中每个结点有一个邮递员,每个邮递员要沿着唯一的路径走向capital(1号结点),每到一个城市他可 ...

  9. 【BZOJ】3963: [WF2011]MachineWorks

    [题意]给定n台在时间di可以买入的机器,pi买入,可在任意时间ri卖出,买入和卖出之间的持有时间每天产生gi金钱,任意时间至多持有一台机器.给定初始钱数c和总天数T,求最大收益.n<=10^5 ...

随机推荐

  1. 从Android手机中取出已安装的app包,导出apk

    从Android手机中取出已安装的app包,导出apk TAG:Android,提取,apk,adb,pm,root,导出apk 假设有这样一个场景,A君看到你手机上一个实用APP,想要安装到自己手机 ...

  2. axios 获取不到数据错误

    1.问题: 打算学习下vue,但是vue-resource作者已经不更新了,并且大家都建议用axios来进行前后端交互,所以就从学习axios开始. 但是在使用 axios 的过程中,自己写的接口竟然 ...

  3. 分享:陆行鸟BGM合集

    第39首是原版哦 https://pan.baidu.com/mbox/homepage?short=pMkAqhX

  4. 剑指offer(2):字符串

    C语言中的字符串 C语言中字符串的存储方式和数组类似,都是连续定长的内存块.字符串数组以\0结尾,所以会比正常数组多一位,char str3[5] = "1234"; //此处赋值 ...

  5. SSM001/构建maven多模块项目

    一.Idea构建maven多模块项目 1.创建maven项目--创建父模块 [1].File->New->Module... [2].点击next,填写:GroupId,ArtifactI ...

  6. [Python3] 012 元组:list,我们不一样!

    目录 0. 元组的独白 1. 元组的创建 2. 元组的特性 (1) 概述 (2) 少废话,上例子 1) 索引 2) 分片 3) 序列运算 4) 成员检测 3. 元组的遍历 (1) 简单总结 (2) 少 ...

  7. JWT详解-(JSON Web Token教程)

    JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法. 一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密 ...

  8. selenium 等待时间3种方式

    强制等待 sleep() -- 最不建议用 缺点:sleep(10)网络不好的情况,到10秒就抛出异常网络很好,1秒钟就响应了,白白等待多9秒 隐式等待 -- 也不是很理想的方法implicitly_ ...

  9. 身为一个小白,看到一篇值得看的文章。讲述小白学习python的6个方法。

    01. Python怎么学?   Python虽然号称非常简单,功能强大!但是再简单,它也是一门编程语言,任何一个编程语言都会包含: 内功,心法和招式,内功心法就是指的算法,数据结构: 招式就是任何一 ...

  10. jQuery的加法运算,val()获取的结果相加变成了字符串连接。

    加法运算 ?想必大家听到这都会不屑了,加法运算这是多么简单的运算.然而有的时候在jQuery也让人挺头疼的. 常规的是: var num1 = 123; var num2=123; var total ...