首页 > 其他分享 >斜率优化dp学习笔记

斜率优化dp学习笔记

时间:2023-07-10 18:45:19浏览次数:58  
标签:le 笔记 times 斜率 猫子 sumC 我们 dp

前置知识

单调队列优化 dp,计算几何基础知识,小学数学。

斜率优化

在 dp 中,我们常常能遇到一类转移方程,其中含有 \(i\) 相关的项与 \(j\) 相关的项的乘积,形如这种形式:

\[f_i=\max_{j<i}\{ f_j+a_ib_j\} \]

我们常见的单调队列优化只能优化只含 \(j\) 项的方程,对于这种方程无能为力。因此我们需要利用斜率优化。

先来看一道例题:


任务安排

\(n\) 个任务排成一个序列在一台机器上等待完成(顺序不得改变),这 \(n\) 个任务被分成若干批,每批包含相邻的若干任务。

从零时刻开始,这些任务被分批加工,第 \(i\) 个任务单独完成所需的时间为 \(t_i\)。在每批任务开始前,机器需要启动时间 \(s\),而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。

每个任务的费用是它的完成时刻乘以一个费用系数 \(c_i\)。请确定一个分组方案,使得总费用最小。

数据范围:\(n\le 5000, t_i, c_i>0\)。

加强版:\(n\le 100000,t_i, c_i>0\)。


先设 \(sumT[i]\) 为 \(t_i\) 的前缀和,\(sumC[i]\) 为 \(c_i\) 的前缀和。

我们可以很容易设计出一个 \(O(n^3)\) 的转移方程:设 \(f[i][j]\) 为前 \(i\) 个任务共分为 \(j\) 段的最小花费。我们就可以列出转移:

\[f[i][j]=\min_{k<i}\{ f[k][j - 1]+(sumT[i]+j\times s)\times(sumC[i]-sumC[k])\} \]

因为状态数为 \(O(n^2)\) 级别,无论如何优化都无法通过加强版

因为时间复杂度太高,我们考虑重新设计状态。设 \(f[i]\) 为前 \(i\) 个任务分为若干段的最小花费,则

\[f[i]=\min _{j<i}\{f[j]+sumT[i]\times (sumC[i]-sumC[j])+s\times (sumC[n]-sumC[j]) \} \]

这个方程运用了一个费用提前计算的思想,最后一项 \(s\times (sumC[n]-sumC[j])\) 表示虽然不知道后面分成了多少段,但是知道当前分这一段会对后面这些项造成这么多影响。这个方程的复杂度为 \(O(n^2)\),可以通过原版数据范围。

为了通过加强版,我们化简一下式子。

\[\begin{aligned} f[i] & = \min _{j<i}\{f[j]+sumT[i]\times (sumC[i]-sumC[j])+s\times (sumC[n]-sumC[j]) \}\\ &=\min _{j<i}\{f[j]+sumT[i]\times sumC[i]-sumT[i]\times sumC[j]+s\times sumC[n]-s\times sumC[j]) \}\\ &=\min _{j<i}\{f[j]-(sumT[i]+s)\times sumC[j]) \}+sumT[i]\times sumC[i]+s\times sumC[n] \end{aligned} \]

我们移一下项,变为:

\[f[i]-sumT[i]\times sumC[i]-s\times sumC[n]=\min _{j<i}\{f[j]-(sumT[i]+s)\times sumC[j]) \} \]

这时就无法化简了,我们考虑下有什么性质。

我们可以设 \(x_j=sumC[j], y_j=f[j], k_i=(sumT[i]+s), b_i=f[i]-sumT[i]\times sumC[i]-s\times sumC[n]\)。(注意下标)这时式子变为:

\[b_i=\min _{j<i}\{y_j-k_i\times x_j \} \]

这就变成了一个一次函数求截距的式子。注意到 \(sumT[i]\times sumC[i]-s\times sumC[n]\) 在 \(i\) 固定时为定值,目前要求 \(f[i]\) 最小值,则问题转化为求截距的最小值。

我们可以把问题放到坐标系中来看:

由于 \(i\) 固定,则斜率 \(k_i\) 固定。我们就可以把问题想象成拿着一条斜率为 \(k_i\) 的直线从下往上平移,第一个到达的点(点的坐标为上面的 \((x_j, y_j)\))则为最佳转移点(这时截距最小)。我们再考虑下什么样的点才能成为最佳转移点。

考虑三个决策点 \(i, j, k(i<j<k)\)。

当 \(k_{i, j}>k_{j, k}\) 时,如图:

显然,这时 \(j\) 不可能成为最佳转移点。

而当 \(k_{i, j} < k_{j, k}\) 时:

这时 \(j\) 可能成为最佳转移点。

因此,对于所有可能成为最佳转移点的点构成的点集,其斜率必然单调递增。这就是一个凸壳。我们只需要维护这个凸壳,然后查找第一个相交的点即可。(第一个相交的点 \(i\) 满足 \(k_{i-1,i}<k\le k_{i, i+1}\))

现在问题变为了:如何维护这个凸壳?

这个问题很简单。只需要用一个单调队列,用类似找二维凸包的方式向外弹出斜率更大的队尾即可。

而题目中还有一个很好的条件:\(t_i>0\)。因此 \(sumT\) 单调递增。我们在寻找相交的点时就可以不断从队头弹出无用决策(斜率小于当前的 \(k\))。

这样就完成了,时间复杂度 \(O(n)\)。

加加强版

题意相同。

数据范围:\(n\le 100000,-512\le t_i \le 512, 0<c_i\le 512\)。


这时 \(t_i\) 不满足单调递增的关系,我们无法每次从队头弹出元素,因为弹出的元素可能会成为以后的最佳转移点。因此我们需要维护整个凸包,在转移时,由于凸包上斜率单调递增,我们可以在单调队列里二分出第一个满足 \(k_{i-1,i}<k\le k_{i, i+1}\) 的凸包上的点,它就是最佳转移点。时间复杂度会多一个 \(\log n\)。

加加加强版

\(t_i, c_i\) 都可能为负数。


这时横坐标和斜率都无法满足单调递增关系,这就意味着我们无法用单调队列动态维护凸包(可能会在中间插入)。这时常见的有三种解决方案:

  1. 平衡树

平衡树可以做到在数列中动态加入数,这时我们可以在平衡树上二分查找最佳转移点。十分好理解,但是难写。

  1. CDQ 分治

我们设 \(\mathrm{CDQ}(l, r)\) 为计算 \([l, r]\) 这段区间的 \(f\) 值。我们先递归计算 \(\mathrm{CDQ}(l, mid)\)。这时假设我们已经计算完了左半边,考虑左半边对右半边的贡献。我们可以将 \([l, mid]\) 的点组成的凸包建出来,因为这一部分已经计算完毕了,所以我们可以直接排序建凸包。

而对于右区间 \([mid + 1,r]\),我们也可以进行按斜率排序处理,这样就可以按照斜率单调递增的做法来弹出队头转移。最后再递归处理右区间 \(\mathrm{CDQ}(mid + 1, r)\)。

注意:处理右区间时不要将右区间的点加入凸包,因为我们计算的只是左区间对右区间的贡献,其余的贡献会继续递归处理。

  1. 李超线段树

我们可以再把转移方程搬过来:

\[f[i]-sumT[i]\times sumC[i]-s\times sumC[n]=\min _{j<i}\{f[j]-(sumT[i]+s)\times sumC[j]) \} \]

这时我们不按照上面的设法,我们重新理解下这个式子。

我们可以理解为有 \(i-1\) 条直线 \(1\sim i-1\),每条直线的斜率为 \(-sumC[j]\),截距为 \(f[j]\),而我们要查询当 \(x=sumT[i]+s\) 时的最值。这个可以直接用李超线段树维护。

习题

Cats Transport

有 \(m\) 只猫子,\(p\) 只铲屎官。有 \(n\) 座山,第 \(i\) 座山与第 \(i-1\) 座山的距离为 \(D_i\)。这些猫子都去玩,猫子 \(i\) 去第 \(H_i\) 座山玩,在 \(T_i\) 时间结束游玩,然后在 \(H_i\) 傻等铲屎官来接它。铲屎官必须把所有猫子都带上,每个铲屎官以每秒 \(1\) 的速度不间断的从 \(H_1\) 走到 \(H_n\)。每个铲屎官可以带上无限的猫子。现在安排每个铲屎官的出发时间(可以为负数),最小化猫子们的等待时间之和。求出最小等待时间之和。

数据范围:\(m\le 100000, p\le 100\)。


我们先设 \(A_i=T_i-\sum_{i=2}^{H_i}D_i\),即猫子能被接到的最早出发时间。因此如果铲屎官从 \(t\) 时刻出发,则这只猫子等待时间则为 \(t-A_i\)。

我们将 \(A_i\) 排序,设 \(s\) 为其排好序后的前缀和。利用临项交换法可以证明,一个铲屎官出发后带走的猫子在 \(A\) 中一定是连续的一段。这时我们就可以把问题转化为上面的任务安排。

我们考虑一只铲屎官带走 \([l, r]\) 这些猫的代价为:

\[\sum\limits _{i=l}^{r}(A_r-A_i)=(r-l+1)A_r-s_r+s_{l-1} \]

我们设 \(f[i][j]\) 为前 \(i\) 只铲屎官带走了前 \(j\) 只猫子,则转移方程为:

\[f[i][j]=\min_{k<j}\{f[i-1][k]+(j-k)A_j-s_j+s_k \} \]

这样复杂度为 \(O(m^2p)\) 的,考虑斜率优化。

我们化简式子,能得到 \(f[i][j]+s_j-j\times A_j=\min_{k<j}\{f[i-1][k]+s_k-A_j\times k\}\)。这样就可以直接斜率优化了。

另外,本题可以加强数据到 \(p\le 100000\)。这时我们可以用 wqs 二分来消去 \(i\) 这一维,使得时间复杂度降为 \(O(m\log p)\)。这里不再介绍。

Building Bridges

有 \(n\) 根柱子依次排列,每根柱子都有一个高度。第 \(i\) 根柱子的高度为 \(h_i\)。

现在想要建造若干座桥,如果一座桥架在第 \(i\) 根柱子和第 \(j\) 根柱子之间,那么需要 \((h_i-h_j)^2\)​​ 的代价。

在造桥前,所有用不到的柱子都会被拆除,因为他们会干扰造桥进程。第 \(i\) 根柱子被拆除的代价为 \(w_i\),注意 \(w_i\) 不一定非负,因为可能政府希望拆除某些柱子。

现在政府想要知道,通过桥梁把第 \(1\) 根柱子和第 \(n\) 根柱子连接的最小代价。注意桥梁不能在端点以外的任何地方相交。

数据范围:\(2\le n\le 10^5;0\le h_i,\vert w_i\vert\le 10^6\)。


本题很容易设出状态并写出转移方程:\(f_i\) 表示 \(1\sim i\) 建桥的代价,则

\[\begin{aligned} f_i & = \min _{j<i}\{f_j+(h_i-h_j)^2+sum_{i-1}-sum_{j} \}\\ &=\min _{j<i}\{f_j-sum_{j}+h_j^2-2h_i\times h_j \}+sum_{i-1}+h_i^2 \end{aligned} \]

这样就化为了斜率优化的形式,由于本题横坐标和斜率都不单调,则需要李超线段树或者 cdq 分治来优化。

The End

标签:le,笔记,times,斜率,猫子,sumC,我们,dp
From: https://www.cnblogs.com/crimsonawa/p/17542009.html

相关文章

  • cdq分治学习笔记
    做着做着cdq分治的题发现自己太菜了写不出来题XD,所以来写写学习笔记。CDQ分治CDQ分治一般有两个用途:解决偏序问题、将动态问题转化为静态问题。偏序问题我们先来介绍第一个问题:偏序问题。普通的二维偏序就类似于逆序对,每个元素有两个属性\(a_i,b_i\),我们需要统计\(a_......
  • 整体二分学习笔记
    整体二分引入对于一堆询问,如果每个单独的询问都可以二分解决的话,时间复杂度为\(O(NM\logN)\),但实际上每次二分都会有一些残留信息被我们扔掉,如果我们将所有询问一起二分,就可以最大时间的减小复杂度。讲解经典例题:区间第k大给定一个序列a和一个整数S,有2种操作:1.将a......
  • Linux系统编程笔记
    系统调用open函数文件打开函数函数原型:intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode)返回值为一个文件描述符参数列表:pathname:文件的完整路径flags:打开文件的模式,常用的模式包括:O_WRONLY:只写模式O_RD......
  • 硬核!阿里2023版Spring全家桶进阶笔记流出,堪称Java跳槽神器
    最近小伙伴在我后台留言是这样的: 现在就这光景,不比以前,会个CRUD就有人要,即使大部分公司依然只需要做CRUD的事情......现在去面试,只会CRUD还要被吐槽: 面试造火箭,工作拧螺丝,就是现在互联网最真实的写照。很多程序员都是死磕八股文,以应对面试。这种情况无可厚非,但其实最重......
  • 【计数,DP】ABC306Ex Balance Scale
    ProblemLink现在有\(n\)个球,每个球有一个重量,重量未知。接下来会进行\(m\)次称重,每次给定\(a_i\)和\(b_i\),比较这两个球的重量,结果可能是\(>,=,<\)中的一种。求在所有\(3^m\)个结果中有几种是可能出现的。\(n\le17,m\len(n-1)/2\)。技巧:怎样配容斥系数将\((a_......
  • 007 学习笔记--约束 + 多表查询
    约束:是作用于表中字段上的规则,用于限制存储在标中的数据;其目的,是保证数据库中的数据的正确、有效和完整性;约束分类:--约束createtableifnotexistsusers( idintPRIMARYkeyauto_incrementCOMMENT'主键', nameVARCHAR(100)notnulluniqueCOMMENT'姓名',--......
  • Cesium学习笔记3——加载topojson和Geojson
    在根目录下新建bucket.css@import"../Build/CesiumUnminified/Widgets/widgets.css";@import"../Build/CesiumUnminified/Widgets/lighter.css";html{height:100%}body{background:#000;color:#eee;font-family:sans-serif;font-size:9pt;padding:0;margin:0;w......
  • Cesium学习笔记4——几何体绘制
    引用:Sandcastle-header.js<!DOCTYPEhtml><htmllang="en"><head><metacharset="utf-8"/><metahttp-equiv="X-UA-Compatible"content="IE=edge"/><metaname="......
  • Transformer学习笔记
    09Transformer之什么是注意力机制(Attention)@水导ELMo原理解析及简单上手使用@知乎ELMo可以解决多义词的词向量,基于LSTM,基础是LSTM和RNN。......
  • 「学习笔记」Lambda 表达式
    Lambda表达式因数学中的\(\lambda\)演算得名,直接对应于其中的lambda抽象.Lambda表达式能够捕获作用域中的变量的无名函数对象,我们可以将其理解为一个匿名的内联函数,可以用来替换独立函数或者函数对象,从而使代码更可读.但是从本质上来讲,Lambda表达式只是一种语......