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. shell脚本一一项目5

    主题:一键查看占用内存.cpu高的进程 echo "----------------cpu top 10 list----------------"ps -eo pid,pcpu, ...

  2. python基础-4.1 open 打开文件练习:修改haproxy配置文件

    1.如何在线上环境优雅的修改配置文件? 配置文件名称ini global log 127.0.0.1 local2 daemon maxconn 256 log 127.0.0.1 local2 in ...

  3. 尝试Vue3.0

    Composition API 纯函数式 <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  4. JavaWeb servlet,乱码的原因和解决

    请求为什么会有乱码? 答:当表单提交时,浏览器对中文参数值进行编码(使用打开表单所在的页面时的字符集进行编码,web服务器在默认情况下会使用iso-8859-1去解码,编码和解码方式不一致,就会产生乱 ...

  5. vue 弹框产生的滚动穿透问题

    首先定义一个全局样式: .noscroll{ position: fixed; left: 0; top: 0; width: 100%; } 创建一个dom.js文件,定义几个方法: export ...

  6. SCUT - 38 - 屠场的秘密 - 分解

    https://scut.online/p/38 要求是2016的倍数,把每个数分解成有2016的倍数和余数,两数余数的乘积是2016的倍数,则原数的乘积也是2016的倍数.

  7. 正在连接localhost...无法打开到主机的连接。 在port 8080: 连接失败

      在cmd中用telnet连接tomcat,出现了"正在连接localhost...无法打开到主机的连接. 在port 8080: 连接失败"原因是我的tomcat是绿色版的,没 ...

  8. mysqldump导入导出

    如果导入数据:使用mysqldump命令 导出数据和表的结构: 1.导出表数据和表结构 mysqldump -u用户名 -p密码 数据库名 > 数据库名.sql(这个名字随便叫) #/usr/l ...

  9. go中string类型转换为基本数据类型的方法

    代码 // string类型转基本数据类型 package main import ( "fmt" "strconv" ) func main() { str1 ...

  10. css盒子模型之边框宽度,边框颜色与边框样式

    /* width和height只是设置盒子内容区的大小,而不是盒子的整个大小, 盒子可见框的大小由内容区,内边距和边框共同决定. */ .box1 { /* 设置内容区的宽度为400px */ wid ...