<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Dynamic Programming |</title><link>https://sichen-wang.github.io/tags/dynamic-programming/</link><atom:link href="https://sichen-wang.github.io/tags/dynamic-programming/index.xml" rel="self" type="application/rss+xml"/><description>Dynamic Programming</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sat, 22 Jun 2024 15:11:24 +0000</lastBuildDate><image><url>https://sichen-wang.github.io/media/icon_hu_9dfcb674aa885f38.png</url><title>Dynamic Programming</title><link>https://sichen-wang.github.io/tags/dynamic-programming/</link></image><item><title>树上背包</title><link>https://sichen-wang.github.io/blog/%E6%A0%91%E4%B8%8A%E8%83%8C%E5%8C%85/</link><pubDate>Sat, 22 Jun 2024 15:11:24 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E6%A0%91%E4%B8%8A%E8%83%8C%E5%8C%85/</guid><description>&lt;h2 id="选取-m-个结点"&gt;选取 m 个结点&lt;/h2&gt;
&lt;p&gt;这是最普遍的情况, 从树中选取 \(m\) 个结点, 最大化它们的价值之和.&lt;/p&gt;
&lt;p&gt;符合直觉地, 设 \(f_{u, i}\) 表示从以 \(u\) 为根的子树中选取了 \(i\) 个结点的最大价值之和. 转移是显然的:&lt;/p&gt;
\[
f_{u, i + j} = \max\{f_{u, i} + f_{v, j}\}
\]&lt;p&gt;其中 \(i\), \(j\) 的范围应当分别为 \(u\) 此前枚举的子树大小和, 以 \(v\) 为根的子树大小.&lt;/p&gt;
&lt;p&gt;其最优性和可行性都是显然的, 我们考虑这个算法的复杂度. 看起来似乎是 \(\Theta(n^{3})\), 但事实上对于任意点对 \((i \in S_{u}, j \in S_{v})\), 它只会在 \(u\) 处被枚举一次. 于是时间复杂度实际上是 \(\Theta(n^{2})\).&lt;/p&gt;
&lt;h2 id="选取结点的代价之和至多为-m"&gt;选取结点的代价之和至多为 m&lt;/h2&gt;
&lt;p&gt;在这个问题中为每个结点引入了代价, 此时上述的复杂度分析不再适用.&lt;/p&gt;
&lt;p&gt;我们不妨考虑换一种思路, 正常的 \(0/1\) 背包复杂度之所以为 \(\Theta(nm)\), 是因为每次只需要对一个物品做是否选取的决策. 在这里, 我们同样考虑将物品独立起来, 只考虑当前物品选或不选. 为了保证无后效性, 接下来的结点编号都被重新设为其在后序遍历中的时间戳.&lt;/p&gt;
&lt;p&gt;设 \(f_{i, j}\) 表示考虑了前 \(i\) 个物品, 背包大小为 \(j\), 能取到的最大价值和.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若选该物品, 则可以选择它子树中的物品, \(f_{i, j} \leftarrow f_{i - 1, j - w_{i}} + v_{i}\).&lt;/li&gt;
&lt;li&gt;若不选该物品, 则它子树内的物品都不可以选, 而子树中的编号恰好是连续的, 于是 \(f_{i, j} \leftarrow f_{i - siz_{i}, j}\).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样转移时间复杂度即为 \(\Theta(nm)\).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nl"&gt;v&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;siz&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dfn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;knapsack_on_tree&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;siz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>某 0/1 背包 Trick</title><link>https://sichen-wang.github.io/blog/%E6%9F%90-01-%E8%83%8C%E5%8C%85-trick/</link><pubDate>Sat, 22 Jun 2024 15:07:48 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E6%9F%90-01-%E8%83%8C%E5%8C%85-trick/</guid><description>&lt;p&gt;有 \(n\) 个物品, 第 \(i\) 个重量为 \(a_{i}\), 求重量不大于 \(c\) 的情况下能够装下的最大重量.&lt;/p&gt;
&lt;p&gt;\(n, m = \max\{a_{i}\} \leqslant 2 \times 10^{4}, c \leqslant 10^{9}.\)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;考虑随便贪心出来一组解 \(y\), 设正确答案为 \(x\), 显然 \(0 \leqslant x - y \leqslant m\).&lt;/p&gt;
&lt;p&gt;考虑求最大的 \(k \leqslant c - y\), 满足存在一种方案, 删除一些贪心方案中选择的物品, 放入一些贪心方案中没有选择的物品, 总重量的变化量为 \(k\). \(y + k\) 即为正确答案.&lt;/p&gt;
&lt;p&gt;设数列 \(\{s_{i}\}\) 为贪心方案中未选的, 数列 \(\{t_{i}\}\) 为贪心方案中选择了的数的相反数, 其中选择 \(t_{i}\) 用以刻画从原方案中删除 \(-t_{i}\).&lt;/p&gt;
&lt;p&gt;注意到以下策略：当且仅当 \(k + s_{i} \leqslant m\) 时才考虑是否选择 \(s_{i}\), 当且仅当 \(k \gt 0\) 时, 才考虑是否从 \(\{t_{i}\}\) 中选数. 容易发现, 不论最终答案如何分布, 一定可以用这种策略刻画出来.&lt;/p&gt;
&lt;p&gt;于是我们发现在转移的过程中, \(|k| \leqslant m\) 始终成立. 因此可以导出一个简单的 \(\rm DP\)：设 \(f_{i, j, k} = 0/1\) 表示当前考虑了 \(s_{1 \sim i}\) 和 \(t_{1 \sim j}\) 中的数, 能否表示 \(k\). 据前文所述策略, 转移是显然的, 时间复杂度为 \(\Theta(n^{2} m)\).&lt;/p&gt;
&lt;p&gt;考虑继续优化, 注意到 \(0/1\) 单独占一个状态表示位非常浪费, 于是设 \(f_{i, k} = j\) 表示在考虑 \(s_{1 \sim i}\) 的情况下, 想要表示 \(k\), 至少还需要考虑 \(t_{1 \sim j}\).&lt;/p&gt;
&lt;p&gt;依据前文策略, 考虑两种转移：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若 \(k + a_{i + 1} \leqslant m\), 则考虑是否选择 \(a_{i + 1}\), 转移到 \(f_{i + 1, k + a_{i + 1}}\) 和 \(f_{i + 1, k}\).&lt;/li&gt;
&lt;li&gt;若 \(k \gt 0\), 则考虑从 \(\{t_{i}\}\) 中选择一个数进行转移, 注意到该下标 \(p \in [f_{i, k} + 1, f_{i - 1, k}]\).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于 \(p\) 的范围, 首先下界是显然的, 因为如果使用 \(t_{f_{i, k}}\) 及之前的数可能会算重. 对于上界, \(f_{i - 1, k}\) 进行同样转移时的下界即为 \(f_{i - 1, k} + 1\), 又因为表示 \(k\) 只需要 \(s_{1 \sim i - 1}\) 中的数即可, 若 \(f_{i, k}\) 进行转移时使用了 \(f_{i - 1, k}\) 转移时使用的同样的 \(\{t_{i}\}\) 中的数, 那么一定是不优的, 故没有必要.&lt;/p&gt;
&lt;p&gt;关于时间复杂度：第一种转移带来的时间复杂度为 \(\Theta(nm)\). 第二种转移中, 对于一个固定的 \(k\), \(p\) 的枚举至多遍历 \(1 \sim |\{t_{i}\}|\) 中每个数至多一遍, 于是该部分时间复杂度也为 \(\Theta(nm)\).&lt;/p&gt;
&lt;p&gt;总时间复杂度为 \(\Theta(nm)\).&lt;/p&gt;</description></item><item><title>决策单调性</title><link>https://sichen-wang.github.io/blog/%E5%86%B3%E7%AD%96%E5%8D%95%E8%B0%83%E6%80%A7/</link><pubDate>Sat, 24 Jun 2023 11:00:56 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E5%86%B3%E7%AD%96%E5%8D%95%E8%B0%83%E6%80%A7/</guid><description>&lt;h2 id="四边形不等式优化"&gt;四边形不等式优化&lt;/h2&gt;
&lt;h3 id="定义"&gt;定义&lt;/h3&gt;
&lt;p&gt;假设有 \(p_{1}\leqslant p_{2}\leqslant p_{3}\leqslant p_{4}.\)&lt;/p&gt;
&lt;p&gt;则 \(c_{p_{1},p_{3}}+c_{p_{2},p_{4}}\leqslant c_{p_{1},p_{4}}+c_{p_{2},p_{3}}\) 被称为四边形不等式。&lt;/p&gt;
&lt;p&gt;假设一个问题满足四边形不等式，那么它的决策点有单调性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proof:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;假设有如下问题 ：现在有一个序列，我们要将其分割开来，分割一段 \([l,r]\) 的代价是 \(c_{l,r}\)，求最小代价。&lt;/p&gt;
&lt;p&gt;设 \(F_{i}\) 表示将前 \(i\) 个位置分割完毕的最小代价，显然有暴力转移 ：&lt;/p&gt;
\[
F_i=\min\limits_{j\lt i}\{F_j+c_{j,i}\}
\]&lt;p&gt;设 \(F_{i}\) 的决策点为 \(p_{i}.\) 假设存在 \(x\gt y,p_{x}\lt p_{y}.\)&lt;/p&gt;
&lt;p&gt;根据最优决策的定义写出这个位置的转移式 :&lt;/p&gt;
\[
F_x=F_{p_x}+c_{p_x,x}\leqslant F_{p_y}+c_{p_y, x}
\]&lt;p&gt;有 \(p_{x}\lt p_{y}\lt y\lt x\)，根据四边形不等式得到 :&lt;/p&gt;
\[
c_{p_x,y}+c_{p_y,x}\leqslant c_{p_y,y}+c_{p_x,x}
\]&lt;p&gt;两不等式相加，得到 :&lt;/p&gt;
\[
F_{p_x}+c_{p_x,y}\leqslant F_{p_y}+c_{p_y,y}
\]&lt;p&gt;与前文矛盾，故不存在 \(x\gt y,p_{x}\lt p_{y}\)，即满足决策单调性。&lt;/p&gt;
&lt;p&gt;需要注意的是，只有最小化问题才能通过四边形不等式判定决策单调性。&lt;/p&gt;
&lt;h3 id="区间形式"&gt;区间形式&lt;/h3&gt;
&lt;p&gt;在实际做题中，我们经常遇到这样的 \(\rm DP\) 方程 ：&lt;/p&gt;
\[
f_{i,j}=\min\limits_{i\leqslant k\lt j}\{f_{i,k}+f_{k+1,j}+w_{i,j}\}
\]&lt;p&gt;我们考虑将四边形不等式推广到二维形式。&lt;/p&gt;
&lt;p&gt;定理 \(1\) ：若 \(w\) 满足四边形不等式，并且对于任意 \(a \leqslant b\leqslant c\leqslant d\)，有 \(w_{a,d}\geqslant w_{b,c}\)，则 \(f\) 也满足四边形不等式。&lt;/p&gt;
&lt;p&gt;定理 \(2\) ：设 \(p_{i,j}\) 表示 \(f_{i,j}\) 的决策点，若 \(f\) 满足四边形不等式，则对于任意 \(i\lt j\)，有 \(p_{i,j-1}\leqslant p_{i,j}\leqslant p_{i+1,j}.\)&lt;/p&gt;
&lt;p&gt;例题 ：
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="转移技巧"&gt;转移技巧&lt;/h2&gt;
&lt;h3 id="有单峰性"&gt;有单峰性&lt;/h3&gt;
&lt;p&gt;这个性质结合决策单调性有均摊转移复杂度 \(\Theta(1)\) 的做法 ：&lt;/p&gt;
&lt;p&gt;记录一个指针表示当前的决策点，由于决策单调性所以它不会往回跳。进入每一层之后如果后面的决策点更优就跳到后面的决策点，根据单峰性这样一定不会漏掉解。&lt;/p&gt;
&lt;p&gt;跳的次数是状态级别的，故转移均摊 \(\Theta(1).\)&lt;/p&gt;
&lt;h3 id="仅有相邻层之间转移"&gt;仅有相邻层之间转移&lt;/h3&gt;
&lt;p&gt;这是一类特殊的二维 \(\rm DP\)，仅有相邻层之间的转移，没有同层之间的转移，同时满足决策单调性。&lt;/p&gt;
&lt;p&gt;一般这种 \(\rm DP\) 的时间复杂度是 \(\Theta(n^{3})\) 的，每次转移需要枚举前一层的所有点。&lt;/p&gt;
&lt;p&gt;我们发现一个性质，在同一层中，先枚举哪一个是无关紧要的，因为同一层之间不会发生转移。&lt;/p&gt;
&lt;p&gt;于是可以考虑分治，先转移 \(mid\)，得到其最优决策为 \(p\)，然后就可以将区间划分开，\([l,mid)\) 和 \((mid,r]\) 分别对应 \([tl,p]\) 和 \([p,tr].\)&lt;/p&gt;
&lt;p&gt;这样分治时间复杂度 \(\Theta(n\log n).\)&lt;/p&gt;
&lt;p&gt;例题 ：
&lt;/p&gt;
&lt;h3 id="贡献难算"&gt;贡献难算&lt;/h3&gt;
&lt;p&gt;首先有例题 ：存在一个长度为 \(n\) 的序列，要将它划分成 \(k\) 段，每段的价值被定义为不同的元素个数，要求最大化贡价值和。&lt;/p&gt;
&lt;p&gt;数据范围：\(n\leqslant 3.5\times 10^{4},k\leqslant 50.\)&lt;/p&gt;
&lt;p&gt;首先有一个 \(\Theta(n^{3k})\) 的暴力 \(\rm DP\)，设 \(dp_{i,j}\) 表示当分到 \(i\) 时已经分了 \(j\) 段的最大价值，有转移式 ：&lt;/p&gt;
\[
dp_{i,j}=\max\limits_{k\lt i}\{dp_{k,j-1}+cnt_{k+1,i}\}
\]&lt;p&gt;其中 \(cnt_{l,r}\) 表示从 \([l,r]\) 中不同颜色的个数，单次计算需要 \(\Theta(n).\)&lt;/p&gt;
&lt;p&gt;我们发现只在相邻层之间发生转移，并且满足决策单调性（直观理解就是分得越多越容易亏），于是可以使用之前提到的分治法。&lt;/p&gt;
&lt;p&gt;这样看起来是优化到 \(\Theta(n^{2k}\log n)\)，但我们考虑计算贡献的具体过程。我们每次只会计算 \(dp_{mid}\) 的值，每次询问一个区间 \([i,mid]\) 的不同元素个数，可以考虑固定右端点移动左端点，容易发现移动次数是当前的分治区间长度，于是总移动次数不会超过 \(n\log n\)，故时间复杂度实际上为 \(\Theta(nk\log n).\)&lt;/p&gt;
&lt;p&gt;例题：
&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="常用算法"&gt;常用算法&lt;/h2&gt;
&lt;h3 id="斜率优化"&gt;斜率优化&lt;/h3&gt;
&lt;p&gt;假设 \(\rm DP\) 方程长成这种形式 ：&lt;/p&gt;
\[
dp_i=\max\limits_{j\lt i}\{dp_j+(i)'+(i)(j)+(j)'+C\}
\]&lt;p&gt;即贡献为一个仅与 \(i\) 有关的式子加上一个仅与 \(j\) 有关的式子加上一个与两者都有关的乘积形式再加上一个常数，那么可以使用斜率优化。&lt;/p&gt;
&lt;p&gt;我们发现 \(dp_{i},(i)',C\) 都与决策点的选择无关，于是可以把它们看作常数，将仅与 \(j\) 有关的式子放在一边，可以得到方程 ：&lt;/p&gt;
\[
dp_j+(j)'=-(i)(j)+dp_i-(i)'-C
\]&lt;p&gt;我们发现这是一次函数的形式，考虑构造平面，平面上有一些点，形如 \(((j),dp_{j}+(j)').\) 我们发现，如果用一条斜率为 \(-(i)\) 的直线经过某个点，那么截距为 \(dp_{i}-(i)'-C.\) 由于我们要最大化 \(dp_{i}\)，等价于最大化这个截距，所以用这根斜率为 \(-(i)\) 的直线从上到下平移，第一个碰到的点就是决策点。&lt;/p&gt;
&lt;p&gt;于是现在问题就变成了维护一个凸包，我们发现有三种情况 ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当加入点按照横坐标单调递增的顺序，并且询问点单调递增时，可以直接维护单调队列，加入点对比队尾斜率，取答案从队首即可。&lt;/li&gt;
&lt;li&gt;当加入点按照横坐标单调的顺序时可以维护一个单调队列，每次加入时对比斜率，取答案二分。&lt;/li&gt;
&lt;li&gt;当加入点无序时直接用平衡树 &lt;code&gt;(std :: set)&lt;/code&gt; 维护，用 &lt;code&gt;lower_bound&lt;/code&gt; 查找插入点，然后向左右两边依次弹出，取答案也使用 &lt;code&gt;lower_bound&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例题 ：
&lt;/p&gt;
&lt;h3 id="二分队列"&gt;二分队列&lt;/h3&gt;
&lt;p&gt;若 \(\rm DP\) 方程形如 ：&lt;/p&gt;
\[
dp_i=\min\limits_{j\lt i}\{dp_j+w_{j+1,i}\}
\]&lt;p&gt;根据决策单调性的推论，任何两个点 \(i,j(i\lt j)\) 之间都存在一个点 \(k\)，在 \(k\) 之前一段转移点为 \(i\)，在 \(k\) 之后某一段转移点为 \(j.\)&lt;/p&gt;
&lt;p&gt;我们发现如果能快速计算 \(w_{i,j}\)，那么就能 \(\Theta(\log n)\) 计算两个点 \(i,j\) 之间的决策分界点。&lt;/p&gt;
&lt;p&gt;我们发现所有相邻决策点的分界点可以用单调队列维护，具体来说 ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;求当前的最优决策时判断一下队首和队次首谁更优，若队首最优则决策点为队首，否则决策点为队次首，并且将当前队首弹出。&lt;/li&gt;
&lt;li&gt;加入一个点时判断它是否能比队尾更快地替换掉队次尾，若能，则弹出队尾，重复操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样就可以快速地维护相邻点的决策分界点了。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(n\log n).\)&lt;/p&gt;
&lt;p&gt;例题 ：
&lt;/p&gt;
&lt;h3 id="二分栈"&gt;二分栈&lt;/h3&gt;
&lt;p&gt;有些题可能会有这样的奇怪性质 ：每个决策点只会被自己前面的点反超。&lt;/p&gt;
&lt;p&gt;我们发现某个决策点会经历这样的过程 ：一开始就比前面的优（否则就相当于一开始就被别人反超了），然后在最优决策的地方呆一会儿，最后被某个点反超。&lt;/p&gt;
&lt;p&gt;严格来说这根本不算决策单调性，但是仍然可以用二分栈来维护，因为两点的优劣仍旧可以 \(\Theta(\log n)\) 对比。具体来说 ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;加入一个点时，若其比堆顶劣，则直接扔掉，若其比堆顶优，则留下。&lt;/li&gt;
&lt;li&gt;每一轮判断一下堆次顶是否比堆顶优，优则将堆顶弹出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样堆顶就一直是当前转移的决策点。&lt;/p&gt;
&lt;p&gt;例题 ：\(\rm [POI2011]Lightning\ Conductor\)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="习题"&gt;习题&lt;/h2&gt;
&lt;h3 id="noi1995-石子合并"&gt;[NOI1995] 石子合并&lt;/h3&gt;
&lt;p&gt;首先有暴力转移 ：&lt;/p&gt;
\[
dp_{l,r}=\min\limits_{i\leqslant k\lt j}\{dp_{i,k}+dp_{k+1,j}+w_{i,j}\}
\]&lt;p&gt;记录前缀和 \(sum\)，这里 \(w_{i,j}=sum_{j}-sum_{i-1}.\)&lt;/p&gt;
&lt;p&gt;\(w\) 显然满足四边形不等式和包含单调，于是考虑四边形不等式优化。&lt;/p&gt;
&lt;p&gt;然后就直接设 \(p_{i,j}\) 表示 \(dp_{i,j}\) 的转移点，成功转移的时候更新，枚举 \(dp_{i,j}\) 断点的时候只需要枚举 \([p_{i,j-1},p_{i+1,j}]\) 即可。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(n^{2}).\)&lt;/p&gt;
&lt;h3 id="sdoi2016征途"&gt;[SDOI2016]征途&lt;/h3&gt;
&lt;p&gt;首先易知，设每一天走的长度为 \(d\)，则答案为 ：&lt;/p&gt;
\[
m\sum_{i=1}^m(d_i-ave)^2=m\sum_{i=1}^md_i^2-\left(\sum_{i=1}^md_i\right)^2
\]&lt;p&gt;容易观察到此题本质上是在求 \(\left(\sum_{i=1}^{m}d_{i}\right)^{2}_{\min}\)，于是设 \(f_{i,j}\) 表示当前已经考虑到第 \(i\) 段，当前已经分成了 \(j\) 段的最小 \(\sum_{p=1}^{j}d_{p}.\) 枚举转移点，容易得到转移方程 ：&lt;/p&gt;
\[
f_{i,j}=\min\limits_{k\lt i}\{f_{k,j-1}+(s_i-s_k)^2\}
\]&lt;p&gt;易证 \(w_{i,j}=(s_{j}-s_{i})^{2}\) 满足四边形不等式，所以该转移方程满足决策单调性。我们还发现转移方程只在相邻层之间转移，所以可以使用分治转移。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(n^{2}\log n).\)&lt;/p&gt;
&lt;p&gt;还有斜率优化的做法，注意到转移方程是可以变形的 ：&lt;/p&gt;
\[
f_{i,j}=f_{k,j-1}+(s_i-s_k)^2
\]\[
\iff f_{i,j}=f_{k,j-1}+s_i^2-2s_is_k+s_k^2
\]\[
\iff f_{k,j-1}+s_k^2=2s_i\cdot s_k+f_{i,j}-s_i^2
\]&lt;p&gt;易知插入点横坐标有序，询问斜率也有序，所以可以直接使用单调队列维护，每一层分开转移。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(n^{2}).\)&lt;/p&gt;
&lt;h3 id="p5574任务分配问题"&gt;[P5574]任务分配问题&lt;/h3&gt;
&lt;p&gt;非常套路的分治 \(+\) 决策单调性优化 \(\rm DP.\)&lt;/p&gt;
&lt;p&gt;首先定义 \(w_{i,j}\) 表示 \(i\sim j\) 的顺序对个数，设 \(f_{i,j}\) 表示当前已经考虑到第 \(i\) 个任务，将他们分成 \(j\) 段的最小顺序对数量之和，易得转移方程 ：&lt;/p&gt;
\[
f_{i,j}=\min\limits_{k\lt i}\{f_{k,j-1}+w_{k+1,i}\}
\]&lt;p&gt;对于任意 \(a\leqslant b\leqslant c\leqslant d\)，使用容斥易证 \(w_{a,c}+w_{b,d}-w_{b,c}\leqslant w_{a,d}\)，故 \(w\) 满足四边形不不等式。进一步的，\(f\) 的转移满足决策单调性。&lt;/p&gt;
&lt;p&gt;有了决策单调性，我们就可以分治转移，同时令人惊喜的是，转移时需要遍历一段连续的区间并计算每一个位置的贡献，于是用莫队和 \(\rm BIT\) 维护一下就好了。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(nk\log^{2n}).\)&lt;/p&gt;</description></item></channel></rss>