斜率优化DP 学习笔记

这篇具有很好参考价值的文章主要介绍了斜率优化DP 学习笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

动态规划——斜率优化DP

适用情况

适用于求解最优解(最大、最小)问题。

可以将转移方程可以化为 \(\left[\begin{array}{rl} 仅与 \space i \space 有关 & 是我们想要最大/最小化的 \\ 仅与 \space j \space 有关 & 是已知的 \\ 与 \space i \space 和 \space j \space 都有关 & 是两项相乘 \end{array}\right]\) 三部分的,
都可以考虑用斜率优化。

形式化的:原式可化为 \(dp_i = \min\limits_{j \in [l,r]}\{ \mathrm y_j - k_ix_j \} - a_i\)
其中 \(y\)\(k\)\(x\) 均为人为规定与 \(dp\) 和常数有关的式子。

应用

前置知识:初中几何

  1. 斜率
    已知两个点 \(\text{A}(x_1, y_1)\)\(\text{B}(x_2, y_2)\),则直线 \(\text{AB}\) 斜率为 \(\dfrac{y_1 - y_2}{x_1 - x_2}\)

  2. 纵截距
    直线 \(y = kx + b\) 的纵截距为 \(b\);即与 \(y\) 轴交点的纵坐标。

  3. 凸壳
    斜率优化DP 学习笔记

求解步骤

\(A_i\)\(B_i\),使状态转移方程转化为 \(f_i = \min(f_j + (A_i - B_j) ^ 2)\)
\(i\)\(j\) 转移来时,丢掉 \(\min\) \(f_i = f_j + {A_i} ^ 2 + {B_j} ^ 2 - 2 \times A_i \times B_j\)
将仅和 \(j\) 有关的放在左边,其他的放在右边 \(f_j + {B_j} ^ 2 = 2 \times A_i \times B_j + f_i - {A_i} ^ 2\)
\(\left\{\begin{array}{ll} y_j &= f_j + {B_j} ^ 2 \\ k_i &= 2 \times A_i \\ x_j &= B_j \\ b_i &= f_i - {A_i} ^ 2 \\ \end{array}\right.\),原式转换为 \(y_j=k_ix_j+b_i\)
转移方程就写作 \(b_i = \min\{ y_j-k_ix_j \}\)

我们把 \((x_j,y_j)\) 看作二维平面上的点,则 \(k_i\) 表示直线斜率,\(b_i\) 表示一条过 \((x_j,y_j)\) 的斜率为 \(k_i\) 的直线的截距;问题转化为,选择合适的 \(j \in [1, i)\),最小化直线的截距。

如图,考虑最 native 的算法:我们将这个斜率为 \(k_i\) 的直线从下往上平移,直到有一个点 \((x_p,y_p)\) 在这条直线上,则有 \(b_i=y_p-k_ix_p\),这时 \(b_i\) 取到最小值。算完 \(f_i\),我们就把 \((x_i,y_i)\) 这个点加入点集中,以做为新的 DP 决策。那么,我们该如何维护点集?

容易发现,此时,\(b_i\) 所能取到最小值的点一定在下凸壳上。因此在寻找 \(p\) 的时候我们不需要枚举所有 \(i-1\) 个点,只需要考虑凸包上的点。

具体的,设 \(K(a,b)\) 表示过 \((x_a,y_a)\)\((x_b,y_b)\) 的直线的斜率。考虑队列 \(q_l,q_{l+1},\ldots,q_r\),维护的是下凸壳上的点。

也就是说,对于 \(l<i<r\),始终有 \(K(q_{i-1},q_i) < K(q_i,q_{i+1})\) 成立;而我们需要找到一个 \(K(q_{e-1},q_e)\le k_i< K(q_e,q_{e+1})\)\(e\)(特别的,当 \(e=l\) 或者 \(e=r\) 时要特别判断)。

一、若 \(k_i\) 关于 \(i\) 单调

可以单调队列维护凸包。

具体的,我们维护一个指针 \(e\) 来计算 \(b_i\) 最小值,即 \(q_e\)\(i\) 的最优决策点,由于 \(k_i\) 是单调的,则 \(e\) 也一定单调,因此 \(e\) 的移动次数是均摊 \(O(1)\) 的。

在插入一个点 \((x_i,y_i)\) 时,我们要判断是否 \(K(q_{r-1},q_r)<K(q_r,i)\),如果不成立(不形成下凸壳)就将 \(q_r\) 弹出,直到等式满足。然后将 \(i\) 插入到 \(q\) 队尾。

这样我们就将 DP 的复杂度优化到了 \(O(n)\);最后概括一下上述斜率优化模板题的算法:

  1. 将初始状态入队。
  2. 每次使用一条和 \(i\) 相关的直线 \(f(i)\) 去切维护的凸包,找到最优决策,更新 \(dp_i\)
  3. 加入状态 \(dp_i\)。如果一个状态(即凸包上的一个点)在 \(dp_i\) 加入后不再是凸包上的点,需要在 \(dp_i\) 加入前将其剔除。

二、若 \(k_i\) 无单调性

可以在凸壳上二分斜率。

直线的斜率没有单调性,则无法确定 \(q_l\) 是否可以弹出队列。

但是不影响原结构(凸壳)的单调性,因此我们在寻找最优决策点,也就是用直线切凸壳的时候,我们将单调队列找队首改为:凸壳上二分。我们二分查找满足 \(K(q_{e-1},q_e)\le k_i< K(q_e,q_{e+1})\) 那条凸壳边,就可以找到最优决策。

三、若 \(x_i\) 无单调性

见:CDQ/平衡树优化DP(未整理)。

示例代码

例题:P3195 玩具装箱。

const int N = 5e4 + 10;

int n, l;
int s[N];
int q[N], dp[N];

int Gx(int k1, int k2) { return (2 * s[k1]) - (2 * s[k2]); }
int Gy(int k1, int k2) { return (dp[k1] + s[k1] * s[k1] + 2 * l * s[k1]) - (dp[k2] + s[k2] * s[k2] + 2 * l * s[k2]); }
int Gv(int i, int j) { return dp[j] + (s[i] - s[j] - l) * (s[i] - s[j] - l); }

signed main() {
    scanf("%lld %lld", &n, &l); ++l;
    for (int i = 1; i <= n; ++i) { scanf("%lld", s + i); s[i] += s[i - 1] + 1; }
    int st = 0, ed = 1;
    for (int i = 1; i <= n; ++i) {
        while (st + 1 < ed && Gy(q[st + 1], q[st]) <= s[i] * Gx(q[st + 1], q[st])) ++st;
        dp[i] = Gv(i, q[st]);
        while (st + 1 < ed && Gx(q[ed - 1], q[ed - 2]) * Gy(i, q[ed - 1]) <= Gx(i, q[ed - 1]) * Gy(q[ed - 1], q[ed - 2])) --ed;
        q[ed++] = i;
    } printf("%lld\n", dp[n]);
    return 0;
}

练习题

见:https://www.luogu.com.cn/training/386804

Reference

[1] https://www.cnblogs.com/littlehb/p/15936381.html
[2] https://oi-wiki.org/dp/opt/slope/文章来源地址https://www.toymoban.com/news/detail-698383.html

到了这里,关于斜率优化DP 学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划——状压DP 学习笔记

    前置知识:位运算 动态规划的过程是随着阶段的增长,在每个状态维度上不断扩展的。 在任意时刻,已经求出最优解的状态与尚未求出最优解的状态在各维度上的分界点组成了 DP 扩展的“轮廓”。对于某些问题,我们需要在动态规划的“状态”中记录一个集合,保存这个“

    2024年02月08日
    浏览(56)
  • 动态规划——树形DP 学习笔记

    前置知识:树基础。 树形 DP,即在树上进行的 DP,最常见的状态表示为 (f_{u,cdots}) ,表示以 (u) 为根的子树的某个东东。 本文将讲解一些经典题目(树的子树个数、树的最大独立集、树的最小点覆盖、树的最小支配集、树的直径、树的重心、树的中心),以及一些常见形

    2024年02月08日
    浏览(38)
  • 动态规划——数位DP 学习笔记

    引入 数位 DP 往往都是这样的题型:给定一个区间 ([l, r]) ,求这个区间中满足某种条件的数的总数。 简单的暴力代码如下: 而当数据规模过大,暴力枚举就 (mathbb T) 飞了,因此引入数位 DP: 概念 数位(digit):对于十进制,即把一个数字按照个位、十位、百位等,一位

    2024年02月08日
    浏览(47)
  • 动态规划——区间DP 学习笔记

    不含四边形不等式优化。 线性动态规划的局限性在于,它只能顺推或倒退,而不能有子区间依赖的问题。 区间动态规划是线性动态规划的扩展,它将问题划分为若干个子区间,并通过定义状态和状态转移方程来求解每个子区间的最优解,最终得到整个区间的最优解。 区间动

    2024年02月08日
    浏览(42)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(43)
  • 15.动态规划:数据结构优化DP

    数据结构优化DP有前缀和、滑动窗口、树状数组、线段树、单调栈、单调队列 中等 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如, [3,6,2,7] 是数组 [0,3,1,6,2,2

    2024年02月03日
    浏览(48)
  • 从01背包开始动态规划:暴力解法 + dp + 滚动数组 + dp优化

        01背包问题是动态规划中最经典的问题之一,本篇将通过给出其四种解法,使读者更深刻理解动态规划。   有N件物品和一个容量是 V 的背包,每个物品有各自的体积和价值,且每个物品只能放一次(这也是01背包名字的由来),如何让背包里装入的物品具有最大的价值总

    2024年04月17日
    浏览(54)
  • 【优化数学模型】2. 动态规划DP方法的求解思路

    多阶段决策问题,就是要在允许的决策范围内,选择一个最优决策使整个系统在预定标准下达到最佳效果。 动态规划 (dynamic programming,DP) 是用来解决多阶段决策过程最优化的一种数量方法。其特点在于,它可以把一个n维决策问题变换为几个一维最优化问题,从而一个一个地去

    2024年02月21日
    浏览(42)
  • 动态规划(DP)(算法笔记)

    本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。 动态规划(Dynamic Programming,DP)是一种用来解决一类最优化问题的算法思想。简单来说,动态规划将一个复杂的问题分解成若干个子

    2024年02月05日
    浏览(47)
  • 【动态规划 状态机dp 性能优化】3098. 求出所有子序列的能量和

    动态规划 状态机dp 性能优化 给你一个长度为 n 的整数数组 nums 和一个 正 整数 k 。 一个子序列的 能量 定义为子序列中 任意 两个元素的差值绝对值的 最小值 。 请你返回 nums 中长度 等于 k 的 所有 子序列的 能量和 。 由于答案可能会很大,将答案对 109 + 7 取余 后返回。 示

    2024年04月27日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包