DP做题笔记

一些博客

一个比较完整的总结

带权二分

决策单调性

未来费用区间DP

做题记录

  • \(f[i][j]\) 表示第 \(i\) 天拥有 \(j\) 张股票的最大收益,不难发现,每一天都不会即买入又卖出,于是就会有三种情况:

    1. 不买不卖:\(f[i][j]=f[i-1][j]\)
    2. 买入:\(f[i][j]=f[i-w-1][k]-AP_i(j-k)\:\:(k\ge j-AS_i)\)
    3. 卖出:\(f[i][j]=f[i-w-1][k]+BP_i(k-j)\:\:(k\le j+BS_i)\)

    其中,\(k\) 枚举的是第 \(i-w-1\) 天拥有的股票数。

    考虑如何优化,以买入为例:

    首先将式子变形,把与 \(k\) 有关的放在一起:

    \[f[i][j]=(f[i-w-1][k]+AP_i\times k)-AP_i\times j\:\:(k\ge j-AS_i) \]

    前半部分其实就是一个滑动窗口了,复杂度 \(O(TMaxP)\)

    参考代码

  • 由于花费只与一组内的最长的长与宽有关,所以我们可以先按照长降序排序之后将有被包含关系(即长宽都小于别人)的矩形删去,廷尉他们是不会造成额外花费的。因此在剩下的矩形中,长都是降序,宽都是升序。

    \(f[i][j]\) 表示前 \(i\) 块地分为 \(j\) 组的最小代价,则有:

    \[f[i][j]=\min_{k<i}\{f[k][j-1]+a_{k+1}\times b_i\} \]

    \(k\)\(x\) 比选 \(y\) 更优,且 \(x>y\),那么:

    \[f[x][j-1]+a_{x+1}\times b_i<f[y][j-1]+a_{y+1}\times b_i \\\frac{f[x][j-1]-f[y][j-1]}{a_{y+1}-a_{x+1}}\le b_i \]

    于是我们得到了一个可以斜率优化的式子,由于 \(b_i\) 递增,所以维护一个下凸壳就可以了。

    参考代码

  • 这是一道决策单调性的题目,可是我并不会证。

    \(f[i]\) 表示前 \(i\) 句话的最小不协调度之和,可以得到:

    \[f[i]=\min_{j<i}\{f[j]+|s_i-s_j-1-L|^{P}\} \]

    其中,\(s_i\) 表示长度前缀和(包括空格),\(-1\) 是因为行末是不包括空格的。

    由于这个转移式具有决策单调性,所以我们使用二分栈(队列)来维护所有的决策点,因为决策单调,所以最优决策点一定是形如\(\{1,1,2,2,2,3,4,4,\cdots\}\) 这样的数列,对于栈中的任意两个点,都可以通过二分来找到一个临界点 \(k\),使得在 \(k\) 之前,通过前一个决策点更优,在 \(k\) 之后,通过后一个决策点更优。

    当我们枚举到 \(i\) 这个位置时,对于队首,只要栈顶与下一个点的临界点小于等于 \(i\),那么弹掉队首,对于队尾,如果倒数第二个点与队尾的临界点大于等于队尾与 \(i\) 的临界点,即这两对点所“负责”的区域发生了重叠,那么弹掉队尾,最后把 \(i\) 入队。而每次的最优决策点即为队首。

    输出有亿点毒瘤……

    参考代码

  • 一道挺好的单调队列优化DP

    \(f[k][i][j]\) 表示在 \(k\) 时段,走到 \((i,j)\) 能获得的最大距离。朴素的DP方程是:

    \[f[k][i][j]=\max\{f[k-1][i][j],f[k][i'][j']+dis(i,j,i',j')\} \]

    其中 \((i',j')\) 是一个在 \(k\) 时段内可以到达 \((i,j)\) 的位置。

    可以用单调队列优化掉 \(j\) 这一维。

    几点注意:

    • 遇到无法到达的点时,清空队列。
    • 四个方向分开讨论(因为他们的起点不同)。
    • 先更新队尾再更新DP值,因为更新队尾元素时要用到上一次的DP值。
    • 最开始将DP数组赋为负无穷(起点除外)。

    参考代码

  • \(f[i]\) 表示到达第 \(i\) 课树时的最小代价,DP方程为:

    \[f[i]=\min_{j<i}\{f[j]+[h_j\le h_i]\}\:\:(i-j\le k) \]

    注意到一个性质:当DP值相同时,用高度小的树转移必然更优,当DP值不同时,用DP值小的树转移更优(因为树高最多使DP值\(+1\))。

    于是就可以单调队列优化了。

  • 易得 \(p[i]=\max\{a_j+\sqrt{|i-j|}\}-a_i\)

    先不管最后的 \(a[i]\),打表可知,前半部分的转移是有决策单调性的。于是我们可以用队列模拟二分栈来解决这一问题。值得注意的是,为了便于计算,我们先假设所有的 \(i\) 都由一个小于自己的 \(j\) 转移过来,也就是说先不管绝对值。为了得到最终的答案,我们还需要把数列反转,再求一遍并取max。

    参考代码

  • 一道带权二分+斜率优化的题目。

    先将题目中要求的式子转化一下:

    \[\begin{split} s^2\times m^2&=m\sum_{i=1}^{m}{(\overline x-x_i)^2} \\&=m\cdot[\sum_{i=1}^{m}{x_i^2+m\overline x^2-2\overline x\sum_{i=1}^{m}{x_i}}] \\&=m\sum_{i=1}^{m}{x_i^2}-(\sum_{i=1}^{m}{x_i})^2 \end{split} \]

    于是问题转化为了使得 \(\sum_{i=1}^{m}{x_i^2}\) 最小。

    \(f[i][j]\) 表示第 \(j\) 天走完 \(i\) 段时上式的最小值。可以得到:

    \[\begin{split} f[i][j]&=\min_{k<i}\{f[k][j-1]+(s_i-s_k)^2\} \\&=\min_{k<i}\{f[k][j-1]+s_k^2-2s_is_j\}+s_i^2 \end{split} \]

    其实推到这里已经可以斜率优化 \(O(mn)\) 通过此题,但还可以优化。

    可以发现 \(f\) 值随着划分次数的增加而减少,因此我们可以采用带权二分的方法去掉 \(j\) 这一维,通过二分分段的权值来使段数逼近 \(m\)。这样做的复杂度是\(O(n\log\sum x_i)\) 的。

    参考代码

  • 这题虽然不用DP,但是需要带权二分,所以也放在这里。

    具体思路是二分给白边附加的权值,再求最小生成树,当选择的白边数量为 \(need\) 时输出答案即可。

    有一些比较恶心的地方:排序的时候要在权值相等时白边优先,二分时应该是 \(l\le r\) 而不是 \(<\)……

    参考代码

  • 四边形优化DP。

    \(f[i][j]\) 表示前 \(i\) 个村庄建 \(j\) 个邮局的最小距离。可以得到:

    \[f[i][j]=\min\{f[k][j-1]+w[k+1][i]\} \]

    其中 \(w[i][j]\) 表示在 \([i,j]\) 中建邮局的最小距离和,它如何计算呢?

    首先有一个结论:若区间长度为奇数,那么将邮局建在中位数处距离和最小;若为偶数,那么建在中间两个之间的任意位置都一样。

    所以,我们可以分类讨论:

    • 若区间长度为奇数:中位数在 \(\frac{i+j}{2}\) 处,相较于 \([i,j-1]\),可以认为中位数没有变化(因为总距离不变),所以总和增加了 \(d[j]-d[\frac{i+j}{2}]\)
    • 若长度为偶数也可以用同样的思路得出同样的结论。

    综上,我们得到了递推式:

    \[w[i][j]=w[i][j-1]+d[j]-d[\frac{i+j}{2}] \]

    然后就是四边形优化的套路了,外层正序枚举 \(j\),内层逆序枚举 \(i\)\(k\) 的范围为 \([s[i][j-1],s[i+1][j]]\)。( \(s\) 表示最优决策点)

    参考代码

  • 考虑给出式子的组合意义,相当于从 \(nk\) 个不同物品中选出 \(t\) 个,且满足 $t\mod k=r $ 的方案数。我们设 \(f[i][j]\) 表示当前考虑到第 \(i\) 个物品,所选数量 \(\mod k\)\(j\) 的方案数,遂于每个物品有选与不选两种选择,所以:

    \[f[i][j]=f[i-1][j]+f[i-1][j-1] \]

    发现每一次转移都只与 \(f[i-1]\) 有关,所以可以矩阵加速,转移矩阵为:

    \[\begin{bmatrix} f_{nk,0}\\ f_{nk,1}\\ f_{nk,2}\\ \vdots \\ f_{nk,k}\\ \end{bmatrix} = \begin{bmatrix} 1 & 0 & \cdots & 0 & 1 \\ 1 & 1 & 0 & \cdots & 0 \\ 0 & 1 & 1 & \cdots & 0 \\ \vdots & \ddots & \ddots & \ddots & \vdots \\ 0 & 0 & \cdots & 1 & 1 \\ \end{bmatrix}^{nk} \begin{bmatrix} 1\\ 0\\ 0\\ \vdots \\ 0\\ \end{bmatrix} \]

    矩阵快速幂即可。

    参考代码

  • 未来费用提前计算的区间DP。

    \(f[i][j][0/1]\) 表示处理完区间 \([i,j]\) 之后在左/右端点时的最小代价,最终答案为 \(\sum{y}-\min\{f[1][n][0],f[1][n][1]\}\)

    当处理完后在左端点时,可以从 \(f[i+1][j][0/1]\) 转移过来,即:

    \[\min \begin{cases} f[i+1][j][0]+(s_i+s_n-s_j)(b_{i+1}.x-b_{i}.x) \\f[i+1][j][1]+(s_i+s_n-s_j)(b_j.x-b_i.x) \end{cases} \]

    在右端点时同理:

    \[\min \begin{cases} f[i][j-1][0]+(s_{i-1}+s_n-s_{j-1})(b_{j}.x-b_{i}.x) \\f[i][j-1][1]+(s_{i-1}+s_n-s_{j-1})(b_j.x-b_{j-1}.x) \end{cases} \]

    老实说,这类问题的思路基本都是这样。

    参考代码

  • 跟上一题几乎一毛一样,注意亿下输出。

    参考代码

  • 与上一题不同的是,本题中可以选择跳过某些不利的点,对此,我们的处理方法是:加维。

    增加一维表示还需要送的人数,每次转移时分别往两边枚举出一个点,钦定当前端点到该点的这一段跳过,这样就可以处理跳过点的情况了。

    用记搜实现会比较方便。

    参考代码

  • 消消乐问题。

    \(f[i]\) 表示 \(i\) 个一样的连在一起的元素被消去后得到的最大分数,可以用完全背包处理。

    然后将连续的一段相同元素合并成一个点,原序列就变成了若干个黑白交错的点,记点 \(i\) 中的元素个数为 \(sz[i]\)

    \(g[l][r][k]\) 表示现在要消玩 \([l,r]\) 这一段点,其中点 $r $ 后面还吊着 \(k\) 个与 \(r\) 相同的元素,那么 \(r\) 可以选择单独消或者与前面的元素一起消。

    单独消:\(g[l][r-1][0]+f[k+sz[r]]\)

    一起消:\(g[i+1][r-1][0]+g[l][i][k+sz[r]]\),其中 \(i\) 是一个颜色与 \(r\) 相同的点。

    同样可以记忆化搜索实现。

    参考代码

  • 又是一道未来费用提前计算的题,方法同上。

    参考代码

  • 四边形优化DP。

    \(f[i][j]\) 表示前 \(i\) 条铁路炸成 \(j\) 段的最小花费,则:

    \[f[i][j]=\min\{f[k][j-1]+w[k+1][i]\} \]

    \(w[i][j]\) 可以递推计算:

    \[w[i][j]=w[i][j-1]+a[j]\times(sum[j-1]-sum[i-1]) \]

    其中 \(sum[i]\) 表示前缀和。

    参考代码

  • 概率期望与DP的结合。

    每一关一小时通过概率为 \(\frac{t_i}{\sum_{x=l_j}^{i}{t_x}}\),故通过这一关的期望时间为 \(\frac{\sum_{x=l_j}^{i}{t_x}}{t_i}\)

    \(w(l,r)\) 表示通过 \([l,r]\) 这一段区间中的关的期望时间,那么:

    \[\begin{split} w(l,r)&=\sum_{x=l}^{r}{\frac{s_x-s_{l-1}}{t_x}} \\&=\sum_{x=l}^{r}{\frac{s_x}{t_x}}-s_{l-1}\sum_{x=l}^{r}{\frac{1}{t_x}} \end{split} \]

    其中 \(s_i\) 表示 \(t\) 的前缀和。

    \(s_i\) 记作 \(s0_i\),将 \(\sum_{x=1}^{i}{\frac{s _x}{t_x}}\) 记作 \(s1_i\)\(\sum_{x=1}^{i}\) 记作 \(s2_i\),那么:

    \[w(l,r)=s1_r-s1_{l-1}-s0_{l-1}(s2_r-s2_{l-1}) \]

    \(f[i][j]\) 表示前 \(i\) 关分为 \(j\) 个等级的最短期望时间,则:

    \[f[i][j]=\min\{f[k][j-1]+w(k+1,i)\} \]

    \(w\) 带入后就可以得到可以斜率优化的式子了。

    参考代码

  • 最短路+DP。

    基本的思路并不难,先处理出总部到各个分部与各个分部到总部的最短路,然后四边形优化DP即可。但是有一点要注意:在处理出每一点往返总部距离之后应将它们排序之后再DP。

    因为每个点对答案的贡献只与其所在集合大小有关,因此,权值小的点应尽量处在一个相对较大的集合中,即在所有集合中,最大的那一个中的点权和应最小,因此要把最小的几个点放入第一个(最大的)集合。所以,对点权排序之后可以让答案最优。

    参考代码

  • 笛卡尔树+DP

    对原序列建立笛卡尔树,节点 \(u\) 的意义就是一个高度为 \(h[fa]-h[u]\) 的横着的极大矩形。不难发现,在两个儿子中放棋子是互不影响的,所以考虑树形DP。

    \(f[i][j]\) 表示第 \(i\) 个节点为根的子树中放了 \(j\) 个棋子的方案数。

    先合并左右子树的答案:

    \[f[i][j]=\sum_{k\le j}{f[v][j-k]\cdot f[i][k]} \]

    其中 \(v\) 表示 \(i\) 的儿子。

    然后还要求对于 \(i\) 节点表示的矩形中放棋子的方案:

    \[f[i][j]=\sum_{k\le j}{f[i][j-k]\cdot k!\cdot \C^k_h\cdot \C^k_{w-j_k}} \]

    其中,\(h,w\) 分别表示长和宽。

    参考代码

  • \(f[i][j]\) 表示到时间 \(r_i\) 时,现在未烤的那一面烤了 \(j\) 分钟的方案数,对于时间段 \([l_i,r_i]\) 就会有如下转移:

    • 不翻面:\(f[i-1][j]\)
    • 翻一次:\(\min \{f[i-1][r_i-j-k]\}+1\),其中,\(k\) 表示当前烤了的这一面在这段时间内烤的时间。
    • 翻两次:\(\min\{f[i-1[j-k]\}+2\),其中,\(k\) 表示当前没烤的那一面在这段时间内烤的时间。

    需要用单调队列优化,枚举的是最优决策点 \(r_i-j-k\)\(j-k\),前者随 \(j\) 的增大而减小,所以要逆推,而后者要顺推。

    还能用滚动数组优化掉 \(i\) 那一维。

    参考代码

posted @ 2021-02-20 15:11  When_C  阅读(92)  评论(0编辑  收藏  举报