题面传送门

首先很明显我们会按照 \(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. javascript-jquery对象的属性处理

    1.attr()方法:获取元素某个属性的值. $("img").attr("title");//获得第一个<img>元素的title属性 $(&qu ...

  2. SpringMvc 中 FrameworkServlet 覆盖 service 的有点。

    @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws Se ...

  3. [no code][scrum meeting] Alpha 11

    项目 内容 会议时间 2020-04-17 会议主题 OCR紧急技术风险分析 会议时长 30min 参会人员 PM+OCR组成员 $( "#cnblogs_post_body" ) ...

  4. [no code][scrum meeting] Beta 3

    $( "#cnblogs_post_body" ).catalog() 例会时间:5月15日11:30,主持者:肖思炀 下次例会时间:5月16日11:30,主持者:伦泽标 一.工作 ...

  5. 2021.9.13考试总结[NOIP模拟52]

    T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...

  6. 表示数值的字符串 牛客网 剑指Offer

    表示数值的字符串 牛客网 剑指Offer 题目描述 请实现一个函数用来判断字符串是否表示数值(包括整数和小数).例如,字符串"+100","5e2"," ...

  7. hdu 5057 Argestes and Sequence (数状数组+离线处理)

    题意: 给N个数.a[1]....a[N]. M种操作: S X Y:令a[X]=Y Q L R D P:查询a[L]...a[R]中满足第D位上数字为P的数的个数 数据范围: 1<=T< ...

  8. SpringCloud升级之路2020.0.x版-29.Spring Cloud OpenFeign 的解析(1)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进行内部域名与服务 ...

  9. Linux 守护进程原理及实例(Redis、Nginx)

    1. 什么是守护进程 守护进程daemon,是指没有控制终端,运行在后台的进程,通常伴随着系统启动产生,系统关机结束.可以使用命令ps -axj查看系统的守护进程,输出如下所示: 父ID PID 组I ...

  10. 『学了就忘』Linux基础命令 — 32、压缩和解压缩相关命令

    目录 1.".zip"格式压缩 2.".gz"格式压缩 3.".bz2"格式压缩 4.".tar"格式打包 5.打包和压 ...