X(j) 和斜率均单调的斜率优化
这是第一次学斜率优化学会的。
例题 [HNOI2008]玩具装箱
题目描述:
P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。
P 教授有编号为 $1 \cdots n$ 的 $n$ 件玩具,第 $i$ 件玩具经过压缩后的一维长度为 $C_i$。
为了方便整理,P 教授要求:
在一个一维容器中的玩具编号是连续的。
同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果将第 $i$ 件玩具到第 $j$ 个玩具放到一个容器中,那么容器的长度将为 $x=j-i+\sum\limits_{k=i}^{j}C_k$。
制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 $x$,其制作费用为 $(x-L)^2$。其中 $L$ 是一个常量。P 教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 $L$。但他希望所有容器的总费用最小。
$1 \leq n \leq 5 \times 10^4$,$1 \leq L \leq 10^7$,$1 \leq C_i \leq 10^7$。
朴素 DP 做法
令状态 $f(i)$ 表示把前 $i$ 个玩具装箱的最小费用,$s(i)$ 为 $c_i$ 的前缀和。
假如将玩具 $j$ 到 $i$ 装在同一箱子,容易列出状态转移方程 $f(i) = \min_{1\le j\le i}{f(j-1)+(i-j+s(i)-s(j-1)-L)^2}$。
直接算的话时间复杂度是 $O(n^2)$,超时。
优化
在计算过程中,$i, s(i), L$ 这些项是已知的,而含有 $j$ 的项如 $f(j-1), j, s(j-1)$ 都是未知的。展开平方式,进行参数分离,定义 $g(i) = i+s(i)-L$,$x(j) = j+s(j-1)$。可选决策 $j$ 的费用记为 $f(i)_j$,则有
$$ f(i)_j = f(j-1)+(g(i)-x(j))^2 = f(j-1) + g(i)^2 - 2 \times g(i) \times x(j) + x(j)^2 $$
式子中 $f(j-1), g(i)^2, x(j)^2$ 这三项中 $i$ 与 $j$ 这两个参数完全分离,但 $2 \times g(i) \times x(j)$ 却没有分离,不像普通单调队列优化的题目那样 「$j_2 > j_1, f(i){j{2}} < f(i){j{1}}$,$j_1$ 就可以删除」这么明显的单调性,需要深入分析。
研究 $j_2 > j_1$ 时 $f(i){j{2}} < f(i){j{1}}$ 即「决策 $j_2$ 优于 决策 $j_1$」的前提条件:
$$ \begin{aligned} f(j_2-1) + g(i)^2 - 2 \times g(i) \times x(j_2) + x(j_2)^2 & < f(j_1-1) + g(i)^2 - 2 \times g(i) \times x(j_1) + x(j_1)^2 \\ (f(j_2-1) + x(j_2)^2) - (f(j_1-1) + x(j_1)^2) & < 2 \times g(i) \times (x(j_2) - x(j_1)) \end{aligned} $$
再令 $y(i) = f(i-1)+x(i)^2$,因 $x(i) = i+s(i-1)$ 是单调递增的,所以 $x(j_2)-x(j_1) > 0$,所以有
$$ \frac{y(j_2) - y(j_1)}{x(j_2)-x(j_1)} < 2 \times g(i) $$
上面式子像 $j_1, j_2$ 两个点形成的斜率,于是用 斜率优化。
斜率优化:计算 $f(i)$ 时,可选决策 $j_2 > j_1$,如果 $j_2$ 比 $j_1$ 优,令 $T(j_1, j_2) = \frac{y(j_2)-y(j_1)}{x(j_2)-x(j_1)}$,则必须满足 $T(j_1, j_2) < 2 \times g(i)$。
该题 $x(i), g(i)$ 都是单调上升的。下面有两个重要结论:
计算 $f(i)$ 时,所有可选决策是 $1, \cdots, i$,可以删除其中的冗余决策,使得队列中从小到大依次存储有价值的可选决策 $j_1, j_2, \cdots, j_k$,使得这些相邻决策之间的斜率都要大于 $2 \times g(i)$。即: $T(j_1, j_2) > 2 \times g(i), T(j_2, j_3) > 2 \times g(i), \cdots, T(j_{k-1}, j_k) > 2 \times g(i)$。最优决策是队首元素 $j_1$。
证明:如果队列中相邻两个决策 $x, y$ 之间的斜率 $T(x, y) < 2 \times g(i)$,由于 $g(i)$ 是单调增的,则对于后面的 $i_1(i_1 > i)$,计算 $f(i_1)$ 时,有:$T(x, y) < 2 \times g(i) < 2 \times g(i_1)$,所以 $y$ 永远比 $x$ 优,$x$ 可以删除。所以 $T(j_1, j_2) > 2 \times g(i), T(j_2, j_3) > 2 \times g(i), \cdots, T(j_{k-1}, j_k) > 2 \times g(i)$。则对于 $f(i)$ 来说,$j_1$ 比 $j_2$ 优,$j_2$ 比 $j_3$ 优,…,$j_{k-1}$ 比 $j_k$ 优,所以队首 $j_1$ 是最优的。并且在 $f(i+1)$ 时可以在之前维护的队列基础上加入新的决策 $i+1$,再继续维护。
可以维护相邻决策之间的斜率单调增。
证明:设队列中三个相邻决策 $j_1, j_2, j_3$,假设出现相邻斜率单调递减的情况,即 $T(j_1, j_2) > T(j_2, j_3)$,分析 $j_2$ 有没有可能在计算 $f$ 的过程中成为最优决策。
$$ j_2 比 j_1 优 \Rightarrow T(j_1, j_2) < 2 \times g(i) \\ j_2 比 j_3 优 \Rightarrow T(j_2, j_3) > 2 \times g(i) \\ T(j_1, j_2) < 2 \times g(i) < T(j_2, j_3) $$
矛盾。所以 $j_2$ 不可能成为最优决策,可以删除。得证。
综上:
- 应该维护队列中相邻决策满足:$2 \times g(i) < T(j_1, j_2) < T(j_2, j_3) < \cdots < T(j_{k-1}, j_k)$。
- 最优决策取队首元素。
程序实现:
- 删尾:要插入新的可选决策 $i$,每次选队列最后两个决策 $j_{k-1}, j_k$,如果 $T(j_{k-1}, j_k) > T(j_k, i)$,则删除队尾元素 $j_k$。循环做下去,直到队列中的元素个数小于 $2$ 或者 $T(j_{k-1}, j_k)<T(j_k, i)$;
- 插入:把新的可选决策 $i$ 加入队尾;
- 删头:取队首两个决策 $j_1, j_2$,如果 $T(j_1, j_2) < 2 \times g(i)$,则删除队首元素 $j_1$。如此循环下去,直到队列中元素个数小于 $2$ 或者 $T(j_1, j_2) > 2 \times g(i)$;
- 取头:最优决策在队首。
时间复杂度是 $O(n)$。
|
|
例题 [APIO2010] 特别行动队
题目描述:
你有一支由 $n$ 名预备役士兵组成的部队,士兵从 $1$ 到 $n$ 编号,你要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如 $(i, i + 1, \cdots i + k)$的序列。所有的队员都应该属于且仅属于一支特别行动队。
编号为 $i$ 的士兵的初始战斗力为 $x_i$ ,一支特别行动队的初始战斗力 $X$ 为队内士兵初始战斗力之和,即 $X = x_i + x_{i+1} + \cdots + x_{i+k}$。
通过长期的观察,你总结出对于一支初始战斗力为 $X$ 的特别行动队,其修正战斗力 $X’= aX^2+bX+c$,其中 $a,~b,~c$ 是已知的系数($a < 0$)。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队的修正战斗力之和最大。试求出这个最大和。
$1 \leq n \leq 10^6$,$-5 \leq a \leq -1$,$-10^7 \leq b \leq 10^7$,$-10^7 \leq c \leq 10^7$,$1 \leq x_i \leq 100$。
分析
令 $f(i)$ 表示把前 $i$ 个士兵编队的最大修正战斗力之和,$s(i)$ 表示 $x_i$ 的前缀和。
假如将士兵 $j$ 到 $i$ 编在同一队,得出状态转移方程 $f(i) = \max_{1\le j\le i}{f(j-1) + a\times (s(i)-s(j-1))^2 + b\times (s(i)-s(j-1)) + c}$。
展开后得出
$$ f(i) = \max_{1\le j\le i}{f(j-1) + a \times s(i)^2 + a \times s(j-1)^2 - 2a \times s(i) \times s(j-1) + b \times s(i) - b \times s(j-1) + c } \\ f(i) = \max_{1\le j\le i}{f(j-1) + a \times (s(i)^2 + s(j-1)^2) - 2a \times s(i) \times s(j-1) + b \times (s(i) - s(j-1)) + c } $$
研究 $j_2 > j_1$ 时 $f(i){j{2}} > f(i){j{1}}$ 即「决策 $j_2$ 优于 决策 $j_1$」的前提条件:
$$ \begin{aligned} f(j_2-1) + a \times (s(i)^2 + s(j_2-1)^2) - 2a \times s(i) \times s(j_2-1) + b \times (s(i) - s(j_2-1)) + c & > f(j_1-1) + a \times (s(i)^2 + s(j_1-1)^2) - 2a \times s(i) \times s(j_1-1) + b \times (s(i) - s(j_1-1)) + c \\ f(j_2-1) - f(j_1-1) + a \times (s(i_2-1)^2 - s(j_1-1)^2) - b \times (s(j_2-1) - s(j_1-1)) & > 2a \times s(i) \times (s(j_2-1) - s(j_1-1)) \\ \frac{f(j_2-1) - f(j_1-1) + a \times (s(i_2-1)^2 - s(j_1-1)^2) - b \times (s(j_2-1) - s(j_1-1))}{s(j_2-1) - s(j_1-1)} & > 2a \times s(i) \end{aligned} $$
令 $g(i) = f(i-1) + a \times s(i-1)^2 - b \times s(i-1)$,则有
$$ \frac{g(j_2)-g(j_1)}{s(j_2-1) - s(j_1-1)} > 2a \times s(i) $$
上面式子就是 $(s(j_1-1), g(j_1)), (s(j_2-1), g(j_2))$ 两个点形成的斜率。
小结:计算 $f(i)$ 时,可选决策 $j_2 > j_1$,令 $T(j_1, j_2)=\frac{g(j_2)-g(j_1)}{s(j_2-1) - s(j_1-1)}$,如果 $j_2$ 比 $j_1$ 优,必须满足 $T(j_1, j_2) > 2a \times s(i)$。
该题 $s(i)$ 单调增,可以得出两个结论:
计算 $f(i)$ 时,可以删除冗余决策,使得队列中从小到大依次存储有价值的可选决策 $j_1, j_2, \cdots, j_k$,使得这些相邻决策之间的斜率都要小于 $2a \times s(i)$。即: $T(j_1, j_2) < 2a \times s(i), T(j_2, j_3) < 2a \times s(i), \cdots, T(j_{k-1}, j_k) < 2a \times s(i)$。最优决策是队首元素 $j_1$。
证明:对于队列中两个相邻决策 $x, y$,如果 $T(x, y) > 2a \times s(i)$,由于 $s(i)$ 单调增,且题目中规定 $a < 0$,所以 $2a \times s(i)$ 单调下降,所以对于 $i_1 > i$ 有 $T(x, y) > 2a \times s(i) > 2a \times s(i_1)$,$y$ 永远比 $x$ 优,所以 $x$ 可以删除。所以 $T(j_1, j_2) < 2a \times s(i), T(j_2, j_3) < 2a \times s(i), \cdots, T(j_{k-1}, j_k) < 2a \times s(i)$,$j_1$ 比 $j_2$ 优,$j_2$ 比 $j_3$ 优,…,$j_k-1$ 比 $j_k$ 优。所以队首元素 $j_1$ 是最优的。
可以维护相邻决策之间的斜率单调减。
证明:设队列中三个相邻决策 $j_1, j_2, j_3$,假设出现单调增即 $T(j_1, j_2) < T(j_2, j_3)$,分析 $j_2$ 有没有可能成为最优决策。
$$ j_2 比 j_1 优 \Rightarrow T(j_1, j_2) > 2a \times s(i) \\ j_2 比 j_3 优 \Rightarrow T(j_2, j_3) < 2a \times s(i) \\ T(j_2, j_3) < 2a \times s(i) < T(j_1, j_2) $$
矛盾。$j_2$ 不可能成为最优决策,可以删除。得证。
综上:
- 应该维护队列中相邻决策满足:$T(j_1, j_2) > T(j_2, j_3) > \cdots > T(j_{k-1}, j_k) > 2a \times s(i)$。
- 最优决策取队首元素。
|
|
更复杂的斜率优化
第二次学习斜率优化。
决策点横坐标 X(j) 不单调
决策点横坐标不单调,维护凸包就不能用单调队列了,因为插入点时可能会插到凸包点集中间的某个位置,而队列不支持这种操作,需要用到平衡树维护或者用 CDQ 分治保证单调性。这里有计算几何基础的话会更易理解,因为上面维护图形时的删点操作与水平序 Graham 扫描法求凸包是类似的,而扫描法的前提为:点集呈水平序,即点从左至右依次排列(体现为 $X(j)$ 单调不减)。(source)
待决策点斜率不单调
如果斜率 $k0[i]$ 不存在单调性该怎么办?(假设此时 $X(j)$ 仍然单调)
我们仍可以用队列维护凸包点集,但不知道每一次会在什么地方取得最优决策点,所以必须要保留整个凸包以确保决策有完整的选择空间,也就是说不能弹走队首,同时查找答案也不能直接取队首,只能使用二分。
列出状态转移方程:$f_i = f_j + s*(cs_n-cs_j)+ts_i*(cs_i-cs_j)$
变换一下得到:$f_j=(s+ts_i)cs_j+f_i-cs_its_i-s*cs_n$
令 $y=f_j, k=(s+ts_i), x=cs_j, b=f_i-cs_its_i-scs_n$,就可以得到一次函数解析式。
转化的方法是把外循环时不能直接得出的(与 $j$ 有关)放在 $x,y$,可以依靠外指针 $i$ 得到的放在 $k,b$。
我们把 $j$ 称作一个决策点,每次选择一个最优决策点来更新 $f_i$ 的值。
对于一个决策点所对应的直线,都可以求得截距 $b$,又因为 $b=f_i-cs_its_i-scs_n$ 中 $cs_its_i-scs_n$ 是固定的,因此 $b$ 越小,$f_i$ 越小。为了让 $f_i$ 尽量小,我们就要求出最小的 $b$。
然后分析单调性。待决策点的横坐标 $x=cs_j$ 是单调递增的。但是由于 $t_i$ 可能为负,斜率 $k=(s+ts_i)$ 不单调。我们依然可以用单调队列(事实上是一个单调栈)维护凸包点集,上凸点依然一定不会成为最优决策点,需维护下凸包。但与前面不一样的地方是不知道当前最优决策点在哪里,所以必须保留整个凸包,不能弹出队首。查找答案时不能直接取队首,要二分查找这样的点:它与左右决策点连线的斜率 $k_1 \lt k \lt k_2$。
|
|
X(j) 与斜率均不单调
Luogu-P4655 [CEOI2017] Building Bridges
列出状态转移方程 $f_i=f_j+h_i^2+h_j^2-2h_ih_j+w_{i-1}-w_j$。
这道题如果用斜率优化做,就要写 CDQ 了,感觉很麻烦。于是换一种思路,把方程变成这样的形式:$f_i = h_i^2+w_{i-1}-2h_jh_i+h_j^2+f_j-w_j$。令 $k=-2h_j, x=h_i, b=h_j^2+f_j-w_j$,就得到 $f_i = h_i^2+w_{i-1}+kx+b$。为了让 $f_i$ 最小,而方程前半部分又是固定的,问题就转化成求 $x=h_i$ 时 $y=kx+b$ 的最小值。可以用李超线段树优化,时间复杂度为 $O(n \log n)$。
|
|
CDQ 的过程:首先将当前区间按照 $id$ 的大小分成左右两个子区间,两个区间内分别按照斜率排序。然后先递归处理左边,结束后左边的 $X(j)$ 是递增的,此时右边还没处理,所以右边的斜率是递增的,然后就转化成最基础的斜率优化了。把左边的点拿出来维护凸包(用单调队列),依次更新右边的点的答案,再递归处理右边,最后将整个区间按照 $X(j)$ 从小到大排序即可。
坑点
- 在计算斜率的函数
double T()
中,一定要用(double)
或者*1.0
,将long long
变成double
类型之后再计算!!!!! - 用
>=
,<=
Q[st]
老是写成st
。- 队列初始化大多都要塞入一个点
P(0)
,比如 玩具装箱 toy,需要塞入P(S[0],dp[0]+(S[0]+L)2)
即P(0,0)
,其代表的决策点为j=0
。手写队列的初始化是st=1,ed=0
,由于塞了初始点导致ed
加 1,所以在一些题解中可以看到h=t=1
甚至是h=t=0
,h=t=2
之类的写法,其实是因为省去了塞初始点的代码。它们都是等价的。 - 当 $X(j)$ 非严格递增时,在求斜率时可能会出现 $X(j1)=X(j2)$ 的情况,此时最好是写成这样的形式:
return Y(j)>=Y(i)?inf:-inf
,而不要直接返回inf
或者−inf
,在某些题中情况较复杂,如果不小心画错了图,返回了一个错误的极值就完了,而且这种错误只用简单数据还很难查出来。
参考资料
🙇