DP做题笔记
一些博客
做题记录
-
设 f[i][j]f[i][j] 表示第 ii 天拥有 jj 张股票的最大收益,不难发现,每一天都不会即买入又卖出,于是就会有三种情况:
- 不买不卖:f[i][j]=f[i−1][j]f[i][j]=f[i−1][j]
- 买入:f[i][j]=f[i−w−1][k]−APi(j−k)(k≥j−ASi)f[i][j]=f[i−w−1][k]−APi(j−k)(k≥j−ASi)
- 卖出:f[i][j]=f[i−w−1][k]+BPi(k−j)(k≤j+BSi)
其中,k 枚举的是第 i−w−1 天拥有的股票数。
考虑如何优化,以买入为例:
首先将式子变形,把与 k 有关的放在一起:
f[i][j]=(f[i−w−1][k]+APi×k)−APi×j(k≥j−ASi)前半部分其实就是一个滑动窗口了,复杂度 O(TMaxP)。
-
由于花费只与一组内的最长的长与宽有关,所以我们可以先按照长降序排序之后将有被包含关系(即长宽都小于别人)的矩形删去,廷尉他们是不会造成额外花费的。因此在剩下的矩形中,长都是降序,宽都是升序。
设 f[i][j] 表示前 i 块地分为 j 组的最小代价,则有:
f[i][j]=mink<i{f[k][j−1]+ak+1×bi}若 k 选 x 比选 y 更优,且 x>y,那么:
f[x][j−1]+ax+1×bi<f[y][j−1]+ay+1×bif[x][j−1]−f[y][j−1]ay+1−ax+1≤bi于是我们得到了一个可以斜率优化的式子,由于 bi 递增,所以维护一个下凸壳就可以了。
-
这是一道决策单调性的题目,可是我并不会证。
设 f[i] 表示前 i 句话的最小不协调度之和,可以得到:
f[i]=minj<i{f[j]+|si−sj−1−L|P}其中,si 表示长度前缀和(包括空格),−1 是因为行末是不包括空格的。
由于这个转移式具有决策单调性,所以我们使用二分栈(队列)来维护所有的决策点,因为决策单调,所以最优决策点一定是形如{1,1,2,2,2,3,4,4,⋯} 这样的数列,对于栈中的任意两个点,都可以通过二分来找到一个临界点 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]=minj<i{f[j]+[hj≤hi]}(i−j≤k)注意到一个性质:当DP值相同时,用高度小的树转移必然更优,当DP值不同时,用DP值小的树转移更优(因为树高最多使DP值+1)。
于是就可以单调队列优化了。
-
易得 p[i]=max{aj+√|i−j|}−ai
先不管最后的 a[i],打表可知,前半部分的转移是有决策单调性的。于是我们可以用队列模拟二分栈来解决这一问题。值得注意的是,为了便于计算,我们先假设所有的 i 都由一个小于自己的 j 转移过来,也就是说先不管绝对值。为了得到最终的答案,我们还需要把数列反转,再求一遍并取max。
-
一道带权二分+斜率优化的题目。
先将题目中要求的式子转化一下:
s2×m2=mm∑i=1(¯x−xi)2=m⋅[m∑i=1x2i+m¯x2−2¯xm∑i=1xi]=mm∑i=1x2i−(m∑i=1xi)2于是问题转化为了使得 ∑mi=1x2i 最小。
令 f[i][j] 表示第 j 天走完 i 段时上式的最小值。可以得到:
f[i][j]=mink<i{f[k][j−1]+(si−sk)2}=mink<i{f[k][j−1]+s2k−2sisj}+s2i其实推到这里已经可以斜率优化 O(mn) 通过此题,但还可以优化。
可以发现 f 值随着划分次数的增加而减少,因此我们可以采用带权二分的方法去掉 j 这一维,通过二分分段的权值来使段数逼近 m。这样做的复杂度是O(nlog∑xi) 的。
-
这题虽然不用DP,但是需要带权二分,所以也放在这里。
具体思路是二分给白边附加的权值,再求最小生成树,当选择的白边数量为 need 时输出答案即可。
有一些比较恶心的地方:排序的时候要在权值相等时白边优先,二分时应该是 l≤r 而不是 <……
-
四边形优化DP。
设 f[i][j] 表示前 i 个村庄建 j 个邮局的最小距离。可以得到:
f[i][j]=min{f[k][j−1]+w[k+1][i]}其中 w[i][j] 表示在 [i,j] 中建邮局的最小距离和,它如何计算呢?
首先有一个结论:若区间长度为奇数,那么将邮局建在中位数处距离和最小;若为偶数,那么建在中间两个之间的任意位置都一样。
所以,我们可以分类讨论:
- 若区间长度为奇数:中位数在 i+j2 处,相较于 [i,j−1],可以认为中位数没有变化(因为总距离不变),所以总和增加了 d[j]−d[i+j2]。
- 若长度为偶数也可以用同样的思路得出同样的结论。
综上,我们得到了递推式:
w[i][j]=w[i][j−1]+d[j]−d[i+j2]然后就是四边形优化的套路了,外层正序枚举 j,内层逆序枚举 i,k 的范围为 [s[i][j−1],s[i+1][j]]。( s 表示最优决策点)
-
考虑给出式子的组合意义,相当于从 nk 个不同物品中选出 t 个,且满足 tmodk=r 的方案数。我们设 f[i][j] 表示当前考虑到第 i 个物品,所选数量 modk 为 j 的方案数,遂于每个物品有选与不选两种选择,所以:
f[i][j]=f[i−1][j]+f[i−1][j−1]发现每一次转移都只与 f[i−1] 有关,所以可以矩阵加速,转移矩阵为:
[fnk,0fnk,1fnk,2⋮fnk,k]=[10⋯01110⋯0011⋯0⋮⋱⋱⋱⋮00⋯11]nk[100⋮0]矩阵快速幂即可。
-
未来费用提前计算的区间DP。
设 f[i][j][0/1] 表示处理完区间 [i,j] 之后在左/右端点时的最小代价,最终答案为 ∑y−min{f[1][n][0],f[1][n][1]}。
当处理完后在左端点时,可以从 f[i+1][j][0/1] 转移过来,即:
min{f[i+1][j][0]+(si+sn−sj)(bi+1.x−bi.x)f[i+1][j][1]+(si+sn−sj)(bj.x−bi.x)在右端点时同理:
min{f[i][j−1][0]+(si−1+sn−sj−1)(bj.x−bi.x)f[i][j−1][1]+(si−1+sn−sj−1)(bj.x−bj−1.x)老实说,这类问题的思路基本都是这样。
-
跟上一题几乎一毛一样,注意亿下输出。
-
与上一题不同的是,本题中可以选择跳过某些不利的点,对此,我们的处理方法是:加维。
增加一维表示还需要送的人数,每次转移时分别往两边枚举出一个点,钦定当前端点到该点的这一段跳过,这样就可以处理跳过点的情况了。
用记搜实现会比较方便。
-
消消乐问题。
令 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]×(sum[j−1]−sum[i−1])其中 sum[i] 表示前缀和。
-
概率期望与DP的结合。
每一关一小时通过概率为 ti∑ix=ljtx,故通过这一关的期望时间为 ∑ix=ljtxti。
令 w(l,r) 表示通过 [l,r] 这一段区间中的关的期望时间,那么:
w(l,r)=r∑x=lsx−sl−1tx=r∑x=lsxtx−sl−1r∑x=l1tx其中 si 表示 t 的前缀和。
将 si 记作 s0i,将 ∑ix=1sxtx 记作 s1i,∑ix=1 记作 s2i,那么:
w(l,r)=s1r−s1l−1−s0l−1(s2r−s2l−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]=∑k≤jf[v][j−k]⋅f[i][k]其中 v 表示 i 的儿子。
然后还要求对于 i 节点表示的矩形中放棋子的方案:
f[i][j]=∑k≤jf[i][j−k]⋅k!⋅Ckh⋅Ckw−jk其中,h,w 分别表示长和宽。
-
令 f[i][j] 表示到时间 ri 时,现在未烤的那一面烤了 j 分钟的方案数,对于时间段 [li,ri] 就会有如下转移:
- 不翻面:f[i−1][j]
- 翻一次:min{f[i−1][ri−j−k]}+1,其中,k 表示当前烤了的这一面在这段时间内烤的时间。
- 翻两次:min{f[i−1[j−k]}+2,其中,k 表示当前没烤的那一面在这段时间内烤的时间。
需要用单调队列优化,枚举的是最优决策点 ri−j−k 和 j−k,前者随 j 的增大而减小,所以要逆推,而后者要顺推。
还能用滚动数组优化掉 i 那一维。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· DeepSeek+PageAssist实现本地大模型联网
· 手把手教你更优雅的享受 DeepSeek
· Java轻量级代码工程
· 从 14 秒到 1 秒:MySQL DDL 性能优化实战