「赛前备战」NOIp2020-提高 动态规划训练

大城市里の小女人 提交于 2020-08-13 18:04:46

博主太菜,可能会炸联赛,于是恶补一下 QAQ

题目比较基础,动态更新

Tags

仅包含 提高组 内容。

  • 类型:

区间 dp背包 dp树形 dp状压 dp计数 dp数位 dp概率/期望 dp环形 dp基环树 dp

  • 优化:

单调栈/单调队列 优化其他数据结构 优化斜率 优化倍增 优化

Summarize

简单总结了部分基础类型的 dp 以及一些优化。

区间 dp

基础状态: \(f(l, r)\) 表示区间 \([l, r]\) ……

基础转移模型示例:\(f(l,r) = \min\limits_{k}\{f(l, k) + f(k+1, r)+\cdots\}\)

基本实现:枚举区间长度,枚举左端点并计算出右端点,枚举断点。或者直接记搜。

树形 dp

树上动态规划。

基础状态:\(f(x, \cdots)\) 表示以 \(x\) 为根的子树……

由于树的递归性质,基本用 Dfs 实现。

状压 dp

常见于元素个数较少的情况。

基础状态:\(f(S, \cdots)\) 表示以 \(x\) 为根的子树……

集合使用二进制、位运算的思想压缩成一个整数并进行判断或转移。

计数 dp

常用于统计方案数。

设计状态是重点,转移看题意。

可能有一些组合计数的知识。

数位 dp

常见情况:统计值域在 \([a, b]\) 中满足……条件的数的个数/数位数字和/……(\(a, b\) 通常很大)

一般拆成 \(\text{ans}(b) - \text{ans}(a - 1)\) 计算,以记忆化搜索实现。

搜索函数的参数一般有当前位置,前面是否有前导零,枚举时是否受当前位大小限制。但大多数题目还会有其他限制。

数位 dp 的复杂度和位数有关。

概率/期望 dp

一般情况下,解决概率问题需要顺序循环,而解决期望问题使用逆序循环,如果定义的状态转移方程存在后效性问题,还需要用到转化成求解方程组的解并使用高斯消元。

部分题目还会牵扯到状压、矩阵加速等。

对分数取模记得逆元。

环形 dp

环上的 dp,一般的处理方法有断环为链然后 dp 两次或 \(n\) 次,或者复制一遍。

基环树 dp

环形 dp + 树形 dp。据说很烦,不会。

背包 dp

主要是挖出经典模型。

单调栈/单调队列 优化

一般会出现滑动最值差不多的模型,如:\(f(i) = \min\limits_{j<i}\{f(j)+\text{val}(i, j) \}\),其中 \(\text{val}(i, j)\) 为一个仅存在关于 \(i\) 或关于 \(j\) 的项的多项式,不存在同时关于 \(i, j\) 的项。

此时可以提出关于 \(i\) 的项,用单调队列维护 \(f(j)\) 和关于 \(j\) 的项,加速转移。

斜率 优化

上述 单调栈/单调队列 优化 的拓展。适用于 \(\text{val}(i, j)\) 中含有同时关于 \(i, j\) 的项时的情况。

一般可以假设来两个决策点 \(a, b(a<b<i)\),并设 \(a\) 劣于 \(b\)。我们可以得到一个不等式,然后变形为 \(\dfrac{y_a - y_b}{x_a - x_b} = \text{slope}(a, b)\) 的形式。最后用单调队列维护上/下凸包即可。

其他数据结构 优化

一般根据转移的特征,使用合适的数据结构优化转移。

倍增 优化

也许会有类似与 \(2^k\) 这种明显的提示。

一般把“转移 \(j\) 次”换成“转移 \(2^k\) 次”降下复杂度。

Content

  • 「eJOI2017」Experience 树形 dp
  • 「eJOI2018」山
  • 「CSP2019-J」纪念品 背包 dp
  • 「NOIp2018-普及」摆渡车
  • 「AHOI2009」中国象棋 计数 dp
  • 「LA 4394」String painter 区间 dp
  • 「CSP2019-S」Emiya 家今天的饭
  • 「Codeforces」Coloring Brackets 区间 dp
  • 「USACO19DEC」Greedy Pie Eaters 区间 dp
  • 「NOIp2018-提高」愤怒的小鸟 状压 dp
  • 「Codeforces 372C」Watching Fireworks is Fun 单调栈/单调队列 优化
  • 「Codeforces 16E」Fish 状压 dp 概率/期望 dp
  • 「POI2014」Little Bird 单调栈/单调队列 优化
  • 「POJ 1746」Minimizing maximizer 其他数据结构 优化 - 线段树
  • 「POJ 2836」Rectangular Covering 状压 dp
  • 「POJ 1821」Fence 单调栈/单调队列 优化
  • 「HDU 3507」Print Article 斜率 优化
  • 「HNOI2008」玩具装箱 斜率 优化
  • 「HDU 2829」Lawrence 斜率 优化
  • 「THUSC 2016」成绩单 区间 dp
  • 「Codeforces 148D」Bag of mice 概率/期望 dp
  • 「Luogu P1654」OSU! 概率/期望 dp
  • 「Luogu P3413」SAC#1 - 萌数 数位 dp
  • 「SDOI2016」征途 斜率 优化
  • 「Luogu P1613」跑路 倍增 优化

「eJOI2017」Experience

update - 2020.7.27

\(f(x, 0), f(x, 1)\) 分别表示以 \(x\) 为根的子树,\(x\) 所在链为向下(非严格)递减、递增时的答案。

题目中要求求极差,那么结点 \(x\) 可能为最大值或最小值。

以向下递减为例,我们在所以满足 \(W_x \ge W_y\) 的所有子结点 \(y\) 中,将原本 \(y\) 的贡献用 \(x\) 作为新的最大值替换,并更新 \(f(x, 0)\) 的答案。向下递增也是同理,不过这里是作为最小值,因此符号会改变。

在做结点 \(x\) 是,我们设 \(p = \sum\limits_{y \in \text{son}(x)} \max(f(y, 0), f(y, 1))\),并令 \(p\)\(f(x, 0), f(x, 1)\) 的初始值。

那么状态转移方程(\(\leftarrow\) 表示最(大)值操作):

\[f(x, 0) \leftarrow \max\limits_{y\in \text{son}(x), W_x \ge W_y}\{p - \max(f(y, 0), f(y, 1)) + W_x - W_y\}\\ f(x, 1) \leftarrow \max\limits_{y\in \text{son}(x), W_x \le W_y}\{p - \max(f(y, 0), f(y, 1)) - W_x + W_y\} \]

时间复杂度 \(O(n)\)

「eJOI2018」山

update - 2020.7.27

\(f(n, k, 0), f(n, k, 1), f(n, k, 2)\) 表示 \([1, n]\) 中,建造了 \(k\) 座房子,且第 \(n-1\),第 \(n\) 个位置的状态分别为 \((0,0),(1, 0), (0, 1)\) 时(\(0\) 表示没有房子,\(1\) 表示有)的最小花费时间。

状态转移方程:

\[f(n, k, 0) = \min\{f(n-1, k, 0), f(n-1, k, 1)\} \\ f(n, k, 1) = f(n-1, k, 2) + \text{get}(a_n - a_{n - 1} + 1)\\ f(n, k, 2) = \min\{f(n-1, k-1, 0) + \text{get}(a_{n-1} - a_n + 1), f(n-1, k-1,1)+\text{get}(\min(a_{n-2}-1, a_{n-1})-a_{i}+1)\}\\ \text{其中 } \text{get}(x)=\max(x, 0) \]

时间复杂度 \(O(n^2)\)

「CSP2019-J」纪念品

update - 2020.7.27

直接存物品的个数显然原地升天。但仔细想一下发现,转换成统一在第 \(i\) 天买,然后在第 \(i+1\) 天卖,其实等价。因为即使对某种物品实际上并不操作,换成全卖了然后买回来也未尝不可。

不难设计出一个比较暴力的状态:\(f(i, j, k)\) 表示第 \(i\) 天,对于前 \(j\) 个物品,剩余现金为 \(k\) 时,下一天手头上的最大现金数。转移方程显然。

为了不空间爆炸,我们尝试优化。第一维显然可以缩掉——我们只要上一轮的最优值即可。剩下了两维看着像一个背包,于是倒序以下就只剩最后一维了。方程:

\[f(k) \leftarrow \max(f(k), f(k - P_{i, k})+P_{i, k+1}-P_{i, k}) \]

时间复杂度 \(O(TN\times \max P)\)

「NOIp2018-普及」摆渡车

update - 2020.7.28

\(t\) 数组升序排序,显然的。设 \(f(i, j)\) 表示第 \(i\) 个人等了 \(j\) 分钟,送走前 \(i\) 个人等待总时间的最小值。

直接看 \(j\) 的范围貌似可以达到 \(\max t\),但其实不然——一个人最多等 \(< 2m\) 分钟。

  • 相比在起点停着 \(m\) 分钟,啥也不管直接开一趟(尽管空车)总不会更劣,那么停车一次不超过 \(T_1 < m\)
  • 一个人等一辆离开的车回来的时间 \(T_2 \le m\)

于是一个人等待的时间 \(j = T_1 + T_2 < 2m\)

那么状态的规模差不多是 \(O(n m)\)。考虑设计转移:

  • \(t_i + j \ge t_{i + 1}\),那么第 \(i+1\) 个人赶得上本趟车,则:\(f(i+1, j+t_i-t_{i+1}) \leftarrow f(i,j)+j+t_i-t_{i+1}\)
  • \(t_i+j+m\ge t_{i+1}\),那么第 \(i+1\) 个人可以在车回来前等车,则枚举车回来的时间 \(k\),转移为: \(f(i+1, j+t_i+m+k-t_{i+1}) \leftarrow f(i, j)+j+t_i+m+k-t_{i+1}\)
  • \(t_i + j + m < t_{i +1}\),那么第 \(i+1\) 个人在车回到起点后到,则枚举第 \(i+1\) 个人的等待时间 \(k\),转移为: \(f(i+1, k) \leftarrow f(i, j)+k\)

时间复杂度:\(O(nm^2)\)

「AHOI2009」中国象棋

update - 2020.7.28

会设状态基本就做完了。设 \(f(i, j, k)\) 表示考虑到第 \(i\) 行,有 \(j\) 列存在一个棋子,\(k\) 列有两个棋子的方案数。

转移非常显然:

  • 不放:\(f(i, j, k) \leftarrow f(i-1, j, k)\)
  • 放在空列:
    • 放一个:\(f(i, j, k) \leftarrow f(i - 1, j - 1, k) \times (m - (j - 1) - k)\)
    • 放两个:\(f(i, j, k) \leftarrow f(i - 1, j - 2, k) \times C_{m - (j - 2) - k}^2\)
  • 放在已经有一个的列:
    • 放一个:\(f(i, j, k) \leftarrow f(i-1, j+1, k-1) \times (j+1)\)
    • 放两个:\(f(i, j, k) \leftarrow f(i - 1, j + 2, k - 2)\times C_{j+2}^2\)
  • 在已有一个的和空列各放一个:\(f(i, j, k) \leftarrow f(i - 1, j, k - 1)\times j \times (m - j - (k - 1))\)

时间复杂度 \(O(nm^2)\)

「LA 4394」String painter

update - 2020.7.28

直接算 \(A, B\) 串不好处理,不如先考虑空串到 \(B\) 的步数。设 \(f(i, j)\) 表示从空串到 \(B[i,j]\) 的最小步数。

那么显然有:

\[f(i,j) = \begin{cases} 0 & i>j\\ 1 & i=j\\ \min\limits_{i < k \le j, B_i = B_k} \{f(i+1, j)+f(k + 1, j)\} & i < j\\ \end{cases} \]

我们令答案为 \(g\)\(g(i)\) 表示 \([1, i]\) 部分的答案。那么:

\[g(i) \leftarrow\min\limits_{0\le j < i} \{g(j) + f(j + 1, i)\}\\ g(i) \leftarrow \min(g(i), g(i - 1)\times [A_i = B_i]) \]

答案为 \(g(n)\),复杂度 \(O(n^3)\)

「CSP2019-S」Emiya 家今天的饭

update - 2020.7.28

分析题目性质,发现不可能有两列或以上占去一半,不合法的只可能是一列。

那么容斥以下,答案等于 总方案数 减去 某一列不合法的方案数。

合法的方案不难处理:\(g(i, j)\) 表示前 \(i\) 行选了 \(j\) 个的方案数,那么显然 \(g(i, j) = g(i - 1, j) + g(i - 1, j - 1)\times \sum_j a_{i,j}\)。可以在 \(O(n^2)\) 时间内解决。

对于不合法的方案,有一个比较暴力的思路,枚举这个不合法列 \(c\),设 \(f(i, j, k)\) 为前 \(i\) 行,在第 \(c\) 列选了 \(j\) 个,其他列选了 \(k\) 个的方案数。那么有转移:

\[f(i, j, k) = f(i - 1, j, k) + f(i - 1, j - 1, k)\times a_{i, c} + (\sum_j a_{i, j} - a_{i, k})\times f(i - 1, j, k - 1) \]

不合法的总数即为所有 \(\sum_{j>k} f(n, j, k)\) 之和。然而这个需要 \(O(n^3 m)\) 的时间,只有 84 分。

突然发现我们只需要 \(j, k\) 之间的差值大小,并不需要具体大小,于是又砍掉一维—— \(f(i, j)\) 表示当不合法列为 \(c\) 时,考虑到前 \(i\) 行,第 \(c\) 列的个数比其他列多 \(j\) 个的方案数。转移方程:

\[f(i, j) = f(i - 1, j) + f(i - 1, j - 1) \times a_{i, c} + f(i - 1, j + 1)\times (\sum_j a_{i, j} - a_{i, c})。 \]

这样时间复杂度 \(O(n^2m)\)

「Codeforces 149D」Coloring Brackets

update - 2020.7.29

显然不能直接用 \(f(l, r)\) 表示区间 \([l, r]\) 的方案数,因为相邻位置也有影响。

于是带上 \(l, r\) 的颜色:\(f(l, r, x, y)\) 表示区间 \([l, r]\) 中,位置 \(l\) 颜色为 \(x\)\(r\)\(y\) 的方案数。颜色 \(0/1/2\) 分别表示无色,蓝色,红色。

那么分三种情况讨论:

  • \(l + 1 = r\):边界条件,\(f(l, r, 0, 1) = f(l, r, 1, 0) = f(l, r, 0, 2) = f(l, r, 2, 0) = 1\)
  • 位置 \(l, r\) 为一组配对的括号:我们可以由区间 \([l + 1, r - 1]\) 的 dp 值推出,转移显然,根据题意模拟即可。
  • 位置 \(l, r\) 为不配对:那么我们可以由两组配对的 dp 值推出。具体地,设位置 \(l\) 的右括号的位置为 \(k\),那么答案就由区间 \([l, k]\)\([k + 1, r]\) 得出。

推荐使用记忆化搜索实现,复杂度 \(O(|s|^2)\)

「USACO19DEC」Greedy Pie Eaters

update - 2020.7.29

\(f(i, j)\) 表示区间 \([i, j]\) 被全部吃完后可得的最大 \(\sum w_i\)。那么有

\[f(i, j)=\max \begin{cases} \max\limits_{i \le k <j} f(i, k) + f(k, j) \\ \max\limits_{i\le k\le j} f(i, k - 1)+f(k + 1, j) +p(i, j, k) \end{cases} \]

其中 \(p(i, j, k)\) 表示所有满足 \(i \le l_x\le k\le r_x\le j\)\(k\)\(w_k\) 的最大值。求 \(p\) 数组可以用向外拓展的方式:

\[p(i-1, j, k) \leftarrow p(i, j, k)\\ p(i, j+1, k) \leftarrow p(i, j, k) \]

在计算 \(p\) 时应先枚举 \(k\)。时间复杂度 \(O(n^3)\)

「NOIp2018-提高」愤怒的小鸟

update - 2020.7.29

众所周知三点确定一条抛物线。那么设 \(s(i, j)\) 表示点 \((x_i, y_i), (x_j, y_j), (0, 0)\) 构成的抛物线上的点集。显然可以 \(O(n^3)\) 预处理。

设计状态:\(f(S)\) 表示覆盖点集 \(S\) 所需的最小抛物线数。转移:

\[f(\varnothing) = 0 \\ f(S \cup s(i, j)) = \min\{f(S) + 1\} \\ f(S \cup (x_i, y_i)) = \min\{f(S) + 1\} \]

这个方法是 \(O(T\times 2^n\cdot n^2)\) 的,非常悬。

考虑一个优化:设 \(x\) 为点集 \(S\) 中没有出现过的最小编号的点的编号,即 \(x = \min\{x|\texttt{S&(1<<(x-1))}=0, x\in \mathbb N^+\}\)。那么可以限定由 \(S\) 拓展的转移的线必定经过第 \(x\) 个点。

这相当于限定了顺序,因为原本乱序枚举与现在可以枚举到的范围其实是一样的。时间复杂度 \(O(T\times 2^n\cdot n)\)

「Codeforces 372C」Watching Fireworks is Fun

update - 2020.7.29

\(f(i, j)\) 表示前 \(i\) 个烟花放完后,当前在位置 \(j\) 处,得到的最大快乐值。那么有:

\[f(i, j) = \max\limits_{|k-j|\le d\times|t_i - t_{i-1}|}\{f(i - 1, k) + b_i - |a_i - j|\} \]

显然这个 dp 是 \(O(n^2m)\) 的,需要优化。

发现这个 \(b\) 可以提出来,那么重新定义 \(f\)

\[f(i, j) = \min\limits_{|k-j|\le d\times|t_i - t_{i-1}|}\{f(i - 1, k) - |a_i - j|\} \]

答案即为 \(\sum b_i - \min f(m, j)\)。又发现可以把 \(|a_i-j|\) 提出来,于是我们发现一个类似于 \(f(i)\) 一段滑动区间的最值问题,显然可以单调队列优化。发现 \(k\) 的范围其实有两段,于是正反各做一次, 时间复杂度 \(O(nm)\)

直接开数组炸空间,于是滚动数组滚掉第一维。

「Codeforces 16E」Fish

update - 2020.7.30

首先要知道 \(x\) 个鱼中任意一对相遇的机率 \(P(x) = \frac{1}{x(x-1)/2}\)

\(n\) 很小,考虑状压——\(f(S)\) 表示存活下来的鱼的集合为 \(S\) 的概率。转移:

\[f(S) = \sum\limits_{i\notin S,j\in S} f(S\cup i) \times a_{j, i} \times \frac{1}{|S|\times(|S| + 1)/2} \]

后面的 \(-1\) 改成了 \(+1\) 是因为原本的集合大小为 \(|S| + 1\)

时间复杂度 \(O(2^n\times n^2)\)

「POI2014」Little Bird

update - 2020.7.30

\(f(i)\) 为到达第 \(i\) 个位置的最小消耗。那么有:

\[f(i) = \min\limits_{j > 0, i - j \le k} \{f(j) + [d_i \ge d_j]\} \]

时间复杂度 \(O(qn\sum k_i)\),直接爆炸。

考虑它是一个滑动最值,那么用单调队列优化这个过程。这里的比较关键字有两个:第一为 \(f\) 的大小,第二为 \(d\) 的大小。

优化后复杂度为 \(O(qn)\),STL 的话可能有点卡常。

「POJ 1746」Minimizing maximizer

update - 2020.7.30

有一个比较朴素的想法:\(f(i, j)\) 表示前 \(i\) 个 Sorter 中,位置 \(j\) 到位置 \(1\) 所需 Sorter 数量的最小值。那么有一个非常显然的转移:

\[f(i, j) = \begin{cases} \min(f(i-1, j),\min\limits_{j\in [s_{i-1}, t_{i-1}]} \{f(i-1, k)\}) & j=t_{i-1}\\ f(i-1, j) & j \ne t_{i-1}\\ \end{cases} \]

\(O(nm)\) 的时空复杂度根本无承受。我们发现第一位明显可以缩掉:

\[f(t_i) \leftarrow \min(f(t_i), \min\limits_{k\in[s_i, t_i]}\{f(k)\} + 1) \]

然而最坏仍然是 \(O(nm)\) 的,于是使用线段树优化区间最值的过程,得到了 \(O(m\log n)\) 的优秀算法。

「POJ 2836」Rectangular Covering

update - 2020.7.30

首先预处理以所有点对为对顶点的矩形的面积和覆盖点集,分别即为 \(s(i, j), p(i, j)\)

\(f(S)\) 为覆盖点集 \(S\) 所需的最小面积。状态转移方程:

\[f(S\cup p(i, j)) = \min\limits_{i\ne j}(f(S\cup p(i, j)), f(S) + s(i, j)) \]

注意共线的特判处理。时间复杂度 \(O(2^n\times n^2)\)

「POJ 1821」Fence

update - 2020.7.31

先将工人按位置 \(S\) 排序。

\(f(i, j)\) 表示前 \(i\) 个工人,处理前 \(j\) 块木板,可得的 \(\sum P_i\) 的最大值。朴素的状态转移:

\[f(i, j) = \max \begin{cases} f(i, j-1) \\ f(i-1, j) \\ \max\limits_{j - L_i\le k\le S_i - 1} \{f(i-1, k) + P_i\times (j-k)\} \end{cases} \]

显然第三个转移是 \(O(n)\) 的,考虑优化。

我们把第三个拆一下:\(f(i, j) = \max\limits_{j - L_i\le k\le S_i - 1} \{f(i-1, k) - P_i\times k\}+P_i\times j\)

发现中间是一个上界固定为 \(S_i - 1\),下界逐渐上升的区间最值问题。于是单调队列优化。

时间复杂度 \(O(nm)\)

「HDU 3507」Print Article

update - 2020.7.31

第一道斜率优化 /cy

若令 \(f(i)\) 表示前 \(i\) 个的最小花费。那么有一个显然的转移:

\[f(i) = \min\limits_{k<i} \{f(k)+(s(i) - s(k))^2+m\}\\ \text{其中}s(i)=\sum_{j=1}^i C_i \]

\(O(n^2)\) 的时耗承受不了,考虑优化。

\(k<j<i\),若决策 \(j\) 优于 \(k\),那么满足不等式

\[f(j)+(s(i)-s(j))^2+m<f(k)+(s(i)-s(k))^2+m \]

化简得

\[2s(i)< \dfrac{[f(k)+s^2(k)]-[f(j)-s^2(j)]}{s(k)-s(j)} \]

我们将 \(j, k\) 抽象成一个二维点 \((x_j, y_j), (x_k, y_k)\),那么设 \(x_t = s(t),y_t = f(t)-s^2(t)\),于是有:

\[2s(i)< \dfrac{y_k - y_j}{x_k - y_k} = \text{slope}(k, j) \]

我们使用斜率优化,用单调队列维护这些点,斜率递增。

当做到第 \(i\) 个时,先弹出队首不符合上述不等式的元素,再将队首直接转移至 \(f(i)\),然后将队尾违背斜率单调性的弹出,最后在尾部插入 \(i\)。弹出时须保证队中存在两个及以上的元素。

时间复杂度 \(O(n)\)

「HNOI2008」玩具装箱

update - 2020.7.31

设前 \(i\) 个的最小花费为 \(f(i)\),则:

\[f(i) = \min\limits_{j < i}\{ f(j) + (i-k-1+s(i)+s(j)-L)^2 \} \\ \text{其中} s(i) = \sum_{j=1}^i C_i \]

为简化计算,设 \(a_t = t + s(t),b_t=t+s(t)+L+1\),于是:

\[f(i) = \min\limits_{j<i} \{ f(j) + a_i^2+b_j^2-2a_i b_j\} \]

对于某个 \(j\),我们将原转移化为:

\[2a_i b_j + f(i) - a_i^2 = f(j) + b_j^2 \]

\(x_t = b_t, y_t = f(t) + b_t^2\),那么这可以被视为一个直线的表达式,为斜率即为 \(2a_i\)

斜率优化,维护一个斜率递增的单调队列即可,第一个满足斜率 \(\text{slope}(j, j+1) >2a_i\)\(j\) 直接转移。

时间复杂度 \(O(n)\)

「HDU 2829」Lawrence

update - 2020.8.1

显然的状态:\(f(i, j)\) 表示前 \(i\) 个站点,炸 \(j\) 次产生的最小值。

显然的方程:\(f(i, j) = \min\limits_{k<i} \{ f(k, j - 1) + c(i)-c(k)-s(k)\times (s(i)-s(k)) \}\),其中 \(s(i) = \sum_{j=1}^i a_i, c(i)\) 表示前 \(i\) 个的两两乘积和,\(=c(i-1)+a(i)s(i-1)\)

单次转移 \(O(n)\),需要优化。设 \(a<b\),且决策 \(a\) 劣于 \(b\),那么有 \(f(a, j-1)-c(a)-s(a)s(i)+s^2(a) > f(b, j-1)-c(b)-s(b)s(i)+s^2(b)\),即:

\[\dfrac{[f(a, j-1)-c(a)+s^2(a)] - [f(b, j-1)-c(b)+s^2(b)]}{s(a)-s(b)} > s(i) \]

\(x_i = s(i), y_i = f(i, j-1)-c(i)+s^2(i)\),那么带入上式:

\[\dfrac{y_a - y_b}{x_a-x_b}= \text{slope}(a, b) > s(i) \]

于是斜率优化。时间复杂度 \(O(nm)\)

「THUSC 2016」成绩单

update - 2020.8.1

考虑区间动规,但显然不是 \(f(i, j)\),因为代价与最值有关,而我们这样是无法知道的。

正确的设法应该是,\(f(i, j, l, r)\) 表示区间 \([i, j]\) 消去部分数,剩下数在值域 \([l, r]\) 中的最小花费。

转移?分类讨论:

  • \(l = r = 0\)。说明我们需要取完,分为直接取完整个区间,或先取这个区间中某段值域的数字:

\[f(i, j, l, r) = \min(a+b\times (\max\limits_{i\le k\le j} w_i - \min\limits_{i\le k\le j} w_i)^2, \min\limits_{x, y} \{f(i, j,x, y)\}+a+b\times (y-x)^2) \]

  • \(l\ne 0\)\(r \ne 0\)。考虑分割这个区间。
    • 当然如果 \(i=j\) 的话只要判断当前值 \(w_i\) 是否 \(\in [l, r]\) 即可。
    • 否则枚举断点 \(k\),左右两部分共有 3 中情况:左边取完,右边取完,都不取完:

\[f(i, j,l, r)\leftarrow f(i, k, l, r) + f(k+1, j, l, r) \\ f(i, j,l, r)\leftarrow f(i, k, 0, 0) + f(k+1, j, l, r) \\ f(i, j,l, r)\leftarrow f(i, k, l, r) + f(k+1, j, 0, 0) \]

可以使用记忆化搜索实现,总复杂度 \(O(n^5)\),但由于状态实际并没有这么多,跑不满。

「Codeforces 148D」Bag of mice

update - 2020.8.3

\(f(i, j)\) 表示轮到公主时,袋中剩下 \(i\) 只白,\(j\) 只黑,公主胜的概率。

首先 \(f(i, j) \leftarrow \frac{i}{i + j}\),即一下就抓到白的的情况。

两人都抓到黑的,中途跑出一只黑的:

\[f(i, j) \leftarrow f(i, j - 3)\times \frac{j}{i +j}\times\frac{j-1}{i+j-1}\times \frac{j-2}{i+j-2} \]

两人都抓到黑的,中途跑出一只白的:

\[f(i, j)\leftarrow f(i -1, j-2) \times \frac{j}{i+j} \times\frac{j-1}{i+j-1} \times \frac{i}{i+j-2} \]

其他败的情况不计算内,复杂度 \(O(w\times b)\)

「Luogu P1654」OSU!

update - 2020.8.3

考虑这样一个等式:\((x+1)^3 = x^3 + 3x^2 + 3x +1\),相比 \(x^3\) 多出了 \(3x^2 + 3x +1\)

\(f(i)\) 为前 \(i\) 个的期望分数。除此之外,还需维护一次方,二次方的期望值 \(\text{E}(x)\)\(\text{E}(x^2)\)

对于一、二次方,有:

\[\text{E}(x) = (\text{E}(x- 1) + 1)\times \text{prob}(i) \\ \text{E}(x^2) = (\text{E}[(x-1)^2] + 2\text{E}(x-1) + 1) \times \text{prob}(i) \]

对于 \(f(i)\) 的计算存在两种情况,当前位置取或不取:

\[f(i) = (f(i-1) + 3\text{E}[(i-1)^2] + 3\text{E}(i-1) + 1) \times \text{prob}(i) + f(i - 1) \times (1-\text{prob}(i)) \\ = f(i-1) + (3\text{E}[(i-1)^2] + 3\text{E}(i-1) + 1) \times \text{prob}(i) \]

\(O(n)\) 递推即可。

「Luogu P3413」SAC#1 - 萌数

update - 2020.8.3

比较复杂的数位 dp。首先不能直接设 \(f(\text{pos}, \text{isPa}, v_0, v_1)\),而应设为 \(f(\text{pos}, \text{isPa}, ex_0, v_0, ex_1, v_1)\)。其中从左至右分别为当前位置,之前是否已经构成回文,前二位是否有效(若为前导 0 则无效),前二位是什么数字,前一位是否有效,前一位是什么数字。多加了两维是为了防止形如 \(\texttt{000041}\) 这种前导 0 构成回文的实际非法的串混进来。

考虑用记忆化搜索实现。在枚举当前位的数字时,需要多计算一个 bool 值:下一次的回文情况(下一个 \(\text{isPa}\))。

由于数位 dp 的重点根本不在方程而是实现,下面给出搜索部分的代码:

LL f[N][2][2][D][2][D];

LL solve(int pos, bool isPa, bool ex0, int val0, bool ex1, int val1, bool lim, bool zero) {
    if (!pos) return LL(isPa);
    if (!lim && !zero && (~f[pos][isPa][ex0][val0][ex1][val1]))
        return f[pos][isPa][ex0][val0][ex1][val1];
    
    LL ret = 0ll; int maxD = lim ? num[pos] - '0' : 9;
    for (int d = 0; d <= maxD; d++) {
        bool nxtPa = (val0 == d && ex0) || (val1 == d && ex1) || isPa;
        bool nxtZr = zero && (d == 0);
        bool nxtLm = lim && (d == maxD);
        (ret += solve(pos - 1, nxtPa, ex1, val1, !nxtZr, d, nxtLm, nxtZr)) %= mod;
    }

    if (!lim && !zero) f[pos][isPa][ex0][val0][ex1][val1] = ret;
    return ret;
}

「SDOI2016」征途

update - 2020.8.4

首先推式子,化简方差:\(v = \dfrac{1}{m}\sum\limits_{i=1}^m v_i^2 - \dfrac{1}{m^2}\left(\sum\limits_{i=1}^m v_i\right)^2\),那么 \(v\times m^2 = m\sum\limits_{i=1}^m v_i^2 - \left(\sum\limits_{i=1}^m v_i\right)^2\)

这个式子的第二项显然不变,着重考虑第一项中的平方和部分。

\(f(t, i)\) 表示走了 \(t\) 段到位置 \(i\) 的最小平方和。那么朴素的转移:

\[f(t, i) = \min\limits_{j<i} \{f(t-1, j) + [s(i) - s(j)]^2\}\\ s \text{为前缀和。} \]

这个 \(O(n)\) 一次的转移显然可以斜率优化。

具体的,我们设 \(a < b\)\(a\) 劣于 \(b\),那么:

\[f(t-1, a) + [s(i) - s(a)]^2 > f(t-1, b) + [s(i) - s(b)]^2 \\ \downarrow \\ \dfrac{[f(t-1, a) + s^2(a)] - [f(t-1, a) + s^2(b)]}{s(a) - s(b)} > 2s(i)\\ \downarrow \\ \text{slope}(a, b) > 2s(i) \]

然后用单调队列维护一个斜率递增的下凸包即可。复杂度 \(O(nm)\)

「Luogu P1613」跑路

update - 2020.8.4

这是一个最短路问题,但真正的图并不是原图。我们设 \(f(u, v)\) 为结点 \(u, v\) 的联通情况,现在需要处理出这个图。

看到 \(2^k\) 就很显然是倍增。设 \(g(u, v, t)\) 为是否存在连接 \(u, v\) 长度为 \(2^t\) 的路径。那么可以用 dp 的方法处理出来:

\[g(i, j, t) = \operatorname\or\limits_{k\in\text{V}} \{ g(i, k, t-1) \and g(k, j, t-1) \} \]

对于 \(f(i, j)\) 的值,若存在一个 \(t\in[0, \log_2(\text{maxlongint})]\),使得 \(g(i, j, k)=\texttt{true}\),那么 \(f(i, j) = 1\),反之则为 \(\infty\)

最后在 \(f\) 上跑 Floyd 即可。时间复杂度 \(O(n^3 \log m)\)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!