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. 如何实现免登陆功能(cookie session?)

    Cookie的机制 Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能. Cookie的Domain和Path属性标识 ...

  2. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_04 IO字节流_10_字节输入流一次读取一个字节的原理

    原理解析 创建一个字节流,指向读取文件的第一个字节.  read找jvm,jvm找os.os去读取硬盘.,读取后指正向后移动一位

  3. Java 之 回调方法

    打个比方,我们点外卖都有到达提醒的服务,顾客自己选择提醒的方式.可以是电话提醒.短信提醒.也可以敲门提醒,这里,“提醒”这个行为是美团或饿了么这样的平台提供的,相当于库函数,但是提醒的方式是由顾客决定 ...

  4. 计算距离的SQL语句

    一,BEGINset @num=6378.138*2*ASIN(SQRT(POW(SIN((lat1*PI()/180-lat2*PI()/180)/2),2)+COS(lat1*PI()/180)* ...

  5. 简述Vue中的计算属性

    1.什么是计算属性 如果模板中的表达式存在过多的逻辑,那么模板会变得臃肿不堪,维护起来也异常困难,因此为了简化逻辑出现了计算属性: <template> <div id=" ...

  6. CTF夺旗赛丨网络内生安全试验场第四季圣诞赛明日开赛!

    期待许久的圣诞狂欢就要来喽 <Jingle bell>欢快的旋律 在耳边翩翩起舞 白胡子老爷爷骑着麋鹿准时来送礼物 2019圣诞节 i 春秋做你的圣诞老人 参加CTF欢乐圣诞赛 你提交答案 ...

  7. Node.js中package.json中库的版本号详解(^和~区别)

    当我们查看package.json中已安装的库的时候,会发现他们的版本号之前都会加一个符号,有的是插入符号(^),有的是波浪符号(~).那么他们到底有什么区别呢?先贴一个例子,对照例子来做解释: &q ...

  8. exec 命令

    source source命令即点(.)命令. 在bash下输入man source,找到source命令解释处,可以看到解释”Read and execute commands from filen ...

  9. hasattr() getattr() setattr() 函数使用详解??

    hasattr(object, name)函数: 判断一个对象里面是否有name属性或者name方法,返回bool值,有name属性(方法)返回True,否则返回False. **注意:name要使用 ...

  10. 2019牛客暑期多校训练营(第五场) - C - generator 2 - BSGS

    https://ac.nowcoder.com/acm/contest/885/C 这个跟平时那种求离散对数的bsgs不一样,虽然可以转化成离散对数来做不过会T掉.展开递推式然后合并具有a的项,发现其 ...