集训Day3-DP优化

单调队列优化DP

单调队列

滑窗最值。队列内维护可能成为答案的值。令队首为当前最优解,其次是次优解,...

每次移动,先将队尾更劣解弹出,再将队首离开边界弹出,最后在队尾插入当前值。这样就可以维护。时间复杂度均摊 \(\Theta(n)\),因为每个元素只会最多出入队各一次。

因为队列内根据优劣顺序单调递减,所以叫单调队列。

一般地,我们为方便边界条件,要记录下标。优劣顺序不一定是比大小,所以可以写比较函数。

模板单调队列

洛谷P3572

简要题意:\(n\) 棵树,高度分别为 \(a_1,a_2,...,a_n\)。小鸟从树 \(1\) 出发,每次可以从树 \(i\) 移动到树 \({i+1},{i+1},...,{i+k}\)。如果目标树的高度大于等于当前树的,那么会增加 \(1\) 点劳累度。求到树 \(n\) 时最小劳累度。

CF372C

简要题意:\(n\) 个编号连续区域,相邻区域距离为 \(1\)。有 \(m\) 个烟花活动在 \(T_i\) 时间、\(a_i\) 位置举办,对于位于 \(x\) 区域的人会获得 \(b_i-|a_i-x|\) 幸福值(可能为负)。每个单位时间可以走 \(d\)。求最大幸福值。\(n\le 1.5\times 10^5,m\le 300\)

\(f_{i,j}\) 表示第 \(i\) 次放烟花时站在 \(j\) 处的累计最大幸福值。则有转移

\[f_{i,j}=\max_{k=j-d\cdot (t_i-t_{i-1})}^{j+d\cdot (t_i-t_{i-1})}f_{i-1,k}+b_i-|a_i-j| \]

因为这个 \(\max\) 区间是滑动窗口,所以可以单调队列优化。
时间复杂度 \(\Theta(nm)\),滚动数组优化后空间 \(\Theta(n)\)

洛谷P2569

简要题意:\(T\) 天内,某只股票在第 \(i\) 天可以以 \(AP_i\) 价买入,以 \(BP_i\) 价卖出,每次买入最多 \(AS_i\) 股,每次卖出最多 \(BS_i\) 股。任意时刻持有数量不超过 \(maxP\),每次买卖行动需间隔 \(W\) 天。\(T,W\le 2000\)

\(f_{i,j}\) 为第 \(i\) 天持有 \(j\) 支股票,当前的直接收益。

为方便处理差价,我们令买入时直接减去买价,卖出时直接加上卖价。分不动、买入、卖出三类讨论,就有一个又臭又长的式子:

\[f_{i,j}=\max\left\{\begin{matrix} f_{i-1,j} \\ \max_{p=j-AS_I}^{j-1} f_{i-W-1,p}-AP_i\cdot (j-p) \\ \max_{p=j+1}^{j+BS_i} f_{i-W-1,p}+BP_i\cdot (p-j) \end{matrix}\right. \]

之所以只取 \(i-W-1\) 天时的取值,是因为我们可以保证它包含了 \(1\sim i-W-1\) 的所有取值。

第二种情况和第三种情况都是滑窗取 \(\max\),用单调队列优化。总时间复杂度为 \(\Theta(T\cdot maxP)\)

多重背包问题

例题:洛谷P1776

给定 \(n\) 种物体,第 \(i\) 种物体有数量 \(m_i\)、价值 \(v_i\)、重量 \(w_i\)。求总重量在 \(W\) 以内最大总价值。\(\sum m_i\le 10^5,n\le 100,W\le 4\times 10^5\)

朴素想法

将每一个物品单独拆开,转为01背包问题。时间复杂度为 \(\Theta(\sum m_i\cdot W)\),不可取。

二进制分组

对于一种物品,我们将其拆成 \(1,2,4,8,16,...,2^k\) 倍的不同单个物品。它就像二进制,可以表示出一个区间:\([0,2^{k+1}-1]\)

假如物品本来一共 \(m_i\) 个,它大于 \(2^{k+1}-1\),也就是还不能表示 \([2^{k+1},m_i]\)。此时我们可以额外加上一个 \(m_i-2^{k+1}+1\) 大小的物品。这样我们就可以用它加上 \([2\cdot 2^{k+1} - m - 1,2^{k+1}-1]\) 的数表示出所有大小,这些数我们已经表示过了。

这样我们就拆出了 \(\log_2 m_i\) 个物品,再01背包。时间复杂度 \(\Theta(\sum \log_2 m_i\cdot W)\)(也就是 \(\Theta(nW\log m_i)\)),可以通过。

单调队列优化

类似01背包/完全背包,我们同样可以列出转移式:

\[f_{i,j}=\max_{k=0}^{m_i} \left(f_{i-1,j-k\cdot w_i}+k\cdot v_i\right) \]

发现它访问的 \(j-k\cdot w_i\) 对于模 \(w_i\) 意义在同位置,考虑将同余位置放在一块看,发现这是一个滑窗,可以单调队列优化。(很不可做的样子?)

这是一个 \(\Theta(nW)\) 的做法。

当然这个式子也有别的方式转成单调队列的形式。

线段树优化DP

LIS

这里讨论DP做法

\[f_i=\max_{j<i,a_j<a_i} f_j+1 \]

这是一个经典 2-side 问题。对于这类二维偏序关系问题,我们的方法很典:扫描线+数据结构。更高维我们需要cdq分治或bitset维护了。

posted @ 2026-08-09 22:00  c_haoc  阅读(4)  评论(0)    收藏  举报