题面传送门

首先很明显我们会按照 \(d_i\) 的顺序从小到大买这些机器,故不管三七二十一先将所有机器按 \(d_i\) 从小到大排序。

考虑 \(dp\),\(dp_i\) 表示在时刻 \(d_i\) 及以前卖掉手头的机器,最多能剩下多少钱。

转移显然就枚举上一个购买的机器编号 \(j\),即 \(dp_i=\max\limits_{j=1}^{i-1}dp_j-p_j+g_j(d_i-d_j-1)+r_j\),其中 \(j\) 可以转移到 \(i\) 当前仅当 \(dp_j\geq p_j\)。最终答案可以选择在某一时刻卖完某个机器后就不再买入新的机器了,即 \(\max\limits_{i=1}^ndp_i\),也可以选择将某个机器用到 \(D\) 天结束,即 \(\max\limits_{i=1}^ndp_i-p_i+g_i(D-d_i)+r_i(dp_i\ge p_i)\)

这样暴力转移是 \(n^2\) 的,但是有一个很明显的优化是这个 \(dp\) 转移满足斜率优化的 \(f_i=d_i+\max a_ib_j+c_j\) 的形式,故考虑斜率优化。考虑两个决策点 \(j,k\) 满足 \(g_j>g_k\),那么从 \(j\) 转移比从 \(k\) 转移更优当前仅当:

\[\begin{aligned}&dp_j-p_j+g_j(d_i-d_j-1)+r_j>dp_k-p_k+g_k(d_i-d_k-1)+r_k\\\Leftrightarrow\ &dp_j-p_j-g_j(d_j+1)+r_j+g_jd_i>dp_k-p_k-g_k(d_k+1)+r_k+g_kd_i\\\Leftrightarrow\ &(dp_j-p_j-g_j(d_j+1)+r_j)-(dp_k-p_k-g_k(d_k+1)+r_k)>d_i(g_k-g_j)\\\Leftrightarrow\ &\dfrac{(dp_j-p_j-g_j(d_j+1)+r_j)-(dp_k-p_k-g_k(d_k+1)+r_k)}{g_j-g_k}>-d_i\end{aligned}
\]

斜率优化转移一下即可。

由于此题 \(g_i\) 不单调,故考虑 CDQ 分治维护斜率优化,具体来说,假设我们要用 \([l,mid]\) 中点的贡献更新 \(dp_{mid+1},dp_{mid+2},\dots,dp_r\),我们将 \([l,mid]\) 中所有满足要求的决策点按 \(g_i\) 从小到大排个序并依次加入凸壳,查找 \(d_i\) 的贡献时就在凸包上二分第一个斜率大于 \(-d_i\) 的点并转移即可。

还有就是对于 \(g_j=g_k\) 的 \(j,k\),相当于平面上坐标为 \(A(g_j,dp_j-p_j-g_j(d_j+1)+r_j),B(g_k,dp_k-p_k-g_k(d_k+1)+r_k)\) 的两点,那么我们对于横坐标相同的点肯定是先将纵坐标小的加入凸包,再将纵坐标大的加入凸包,因此在排序过程中要按\(g_j\) 为第一关键字,\(dp_j-p_j-g_j(d_j+1)+r_j\) 为第二关键字排序。我因此 WA 了好多好多发,xtbz。

这是萌新第二次写 CDQ 分治维护斜率优化哦,大佬不喜勿喷

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e5;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,c,d,Casen=0;
struct event{
int d,p,r,g,id;
bool operator <(const event &rhs){
return d<rhs.d;
}
} a[MAXN+5],tmp[MAXN+5];
ll dp[MAXN+5];
int q[MAXN+5],tl=0;
double slope(int j,int k){
if(a[j].g==a[k].g) return INF;
return 1.0*((dp[j]-1ll*a[j].d*a[j].g-a[j].g+a[j].r-a[j].p)-(dp[k]-1ll*a[k].d*a[k].g-a[k].g+a[k].r-a[k].p))/(a[j].g-a[k].g);
}
int bsearch(int l,int r,int sl){
if(l==r) return l;int mid=l+r>>1;
if(slope(q[mid],q[mid+1])>sl) return bsearch(mid+1,r,sl);
else return bsearch(l,mid,sl);
}
void cdq(int l,int r){
if(l==r){chkmax(dp[l],dp[l-1]);return;}
int mid=l+r>>1;cdq(l,mid);for(int i=l;i<=mid;i++) tmp[i]=a[i];
sort(tmp+l,tmp+mid+1,[](event lhs,event rhs){
if(lhs.g^rhs.g) return lhs.g<rhs.g;int j=lhs.id,k=rhs.id;
return (dp[j]-1ll*a[j].d*a[j].g-a[j].g+a[j].r-a[j].p)<(dp[k]-1ll*a[k].d*a[k].g-a[k].g+a[k].r-a[k].p);
});
tl=0;
for(int i=l;i<=mid;i++){
if(dp[tmp[i].id]<tmp[i].p) continue;
while(tl&&slope(q[tl],tmp[i].id)>slope(q[tl-1],q[tl])) tl--;
q[++tl]=tmp[i].id;
}
for(int i=mid+1;i<=r;i++){
if(!tl) continue;
int pos=bsearch(1,tl,-a[i].d),id=q[pos];
chkmax(dp[i],dp[id]+1ll*(a[i].d-a[id].d-1)*a[id].g+a[id].r-a[id].p);
// printf("%d %d\n",i,id);
}
cdq(mid+1,r);
}
void solve(){
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&a[i].d,&a[i].p,&a[i].r,&a[i].g);
} sort(a+1,a+n+1);
for(int i=1;i<=n;i++) a[i].id=i;
memset(dp,0,sizeof(dp));
ll ans=c;dp[0]=c;cdq(1,n);
for(int i=1;i<=n;i++) if(dp[i]>=a[i].p)
chkmax(ans,dp[i]+a[i].r+1ll*(d-a[i].d)*a[i].g-a[i].p);
for(int i=1;i<=n;i++) chkmax(ans,dp[i]);
printf("Case %d: %lld\n",++Casen,ans);
}
int main(){
while(~scanf("%d%d%d",&n,&c,&d)){
if(!n||!c||!d) break;solve();
}
return 0;
}

Codeforces Gym 101175F - Machine Works(CDQ 分治维护斜率优化)的更多相关文章

  1. hdu 3842 Machine Works(cdq分治维护凸壳)

    题目链接:hdu 3842 Machine Works 详细题解: HDU 3842 Machine Works cdq分治 斜率优化 细节比较多,好好体会一下. 在维护斜率的时候要考虑x1与x2是否 ...

  2. LOJ 2353 & 洛谷 P4027 [NOI2007]货币兑换(CDQ 分治维护斜率优化)

    题目传送门 纪念一下第一道(?)自己 yy 出来的 NOI 题. 考虑 dp,\(dp[i]\) 表示到第 \(i\) 天最多有多少钱. 那么有 \(dp[i]=\max\{\max\limits_{ ...

  3. [NOI2007]货币兑换 cdq分治,斜率优化

    [NOI2007]货币兑换 LG传送门 妥妥的\(n \log n\)cdq做法. 这题用cdq分治也可以\(n \log n\)但是在洛谷上竟然比一些优秀的splay跑得慢真是见了鬼了看来还是人丑常 ...

  4. [NOI2007]货币兑换 「CDQ分治实现斜率优化」

    首先每次买卖一定是在某天 $k$ 以当时的最大收入买入,再到第 $i$ 天卖出,那么易得方程: $$f_i = \max \{\frac{A_iRate_kf_k}{A_kRate_k + B_k} ...

  5. BZOJ1492: [NOI2007]货币兑换Cash(CDQ分治,斜率优化动态规划)

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

  6. Codeforces 848C Goodbye Souvenir(CDQ 分治)

    题面传送门 考虑记录每个点的前驱 \(pre_x\),显然答案为 \(\sum\limits_{i=l}^{r} i-pre_i (pre_i \geq l)\) 我们建立一个平面直角坐标系,\(x\ ...

  7. 【BZOJ4311】向量(线段树分治,斜率优化)

    [BZOJ4311]向量(线段树分治,斜率优化) 题面 BZOJ 题解 先考虑对于给定的向量集,如何求解和当前向量的最大内积. 设当前向量\((x,y)\),有两个不同的向量\((u1,v1),(u2 ...

  8. Codeforces 1093E Intersection of Permutations [CDQ分治]

    洛谷 Codeforces 思路 一开始想到莫队+bitset,发现要T. 再想到分块+bitset,脑子一抽竟然直接开始写了,当然也T了. 最后发现这就是个裸的CDQ分治-- 发现\(a\)不变,可 ...

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

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

随机推荐

  1. 脚本注入1(boolean&&get)

    现在,我们回到之前,练习脚本支持的布尔盲注(get型). 布尔盲注的应用场景是查询成功和失败时回显不同,且存在注入点的地方. 这里以Less-8为例: 发现查询成功时,会显示:失败则无回显. 同时发现 ...

  2. Tekton+Argocd实现自动化流水线

    目录 什么是tekton 安装tekton 安装Dashboard Tekton提供的CRD 安装argocd 创建argocd 安装客户端 连接argocd server 创建App 集群中查看效果 ...

  3. Matlab/Modelsim图像联合仿真平台

    FPGA图像仿真平台 1 引言 在使用modelsim进行图像算法的功能仿真时,无法得到图像的实时预览,因此直观性有所欠缺.因此可配合matlab使用,通过modelsim读出txt格式的图像,利用m ...

  4. QG-2019-AAAI-Improving Neural Question Generation using Answer Separation

    Improving Neural Question Generation using Answer Separation 本篇是2019年发表在AAAI上的一篇文章.该文章在基础的seq2seq模型的 ...

  5. k8s replicaset controller 分析(3)-expectations 机制分析

    replicaset controller分析 replicaset controller简介 replicaset controller是kube-controller-manager组件中众多控制 ...

  6. zuul的各种配置

    我们知道我们前台要展示数据给用户看,这中间可能涉及到从后端的多个微服务进行获取数据.比如获取用户信息需要用到用户微服务.获取商品信息需要获取商品微服务.创建订单需要调用订单微服务,而各个微服务可能分布 ...

  7. 今天学习了BootStrap

    今天学习了BootStrap 一.BootStrap介绍 Bootstrap是一个前端开发的框架,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.Java ...

  8. 正则表达式匹配 牛客网 剑指Offer

    正则表达式匹配 牛客网 剑指Offer 题目描述 请实现一个函数用来匹配包括'.'和''的正则表达式.模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次). 在本题中, ...

  9. JAVA笔记12__字节、字符缓冲流/打印流/对象流/

    /** * !!:以后写流的时候一定要加入缓冲!! * 对文件或其它目标频繁的读写操作,效率低,性能差. * 缓冲流:好处是能更高效地读写信息,原理是将数据先缓冲起来,然后一起写入或读取出来. * * ...

  10. hdu 2176 取(m堆)石子游戏 (裸Nim)

    题意: m堆石头,每堆石头个数:a[1]....a[m]. 每次只能在一堆里取,至少取一个. 最后没石子取者负. 先取者负输出NO,先取胜胜输出YES,然后输出先取者第1次取子的所有方法.如果从有a个 ...