基础动态规划
例 1.1:[NOIP2010 提高组] 乌龟棋 - 洛谷
记录 f[i][j][k][l] 表示每种卡片用的个数即可,距离可以现算。
评测记录 - 洛谷
例 1.2:[HAOI2006]数字序列 - 洛谷
开始想了个 n∗maxa[i] 的屑做法,只有 27 pts,评测记录 - 洛谷 。
正解:可以保留 a[i] 和 a[j] 的充分必要条件是 a[j]−a[i]≥j−i,(j>=i)
移项得 a[j]−j≥a[i]−i ,设 b[i]=a[i]−i,问题一就转化为求 b[i] 的最长不下降子序列。
对于第二问,设 prei 表示 bi 由 bprei 转移而来。
Lemma: bi 和 bprei 存在一个分界点 k 满足 ∀j∈[bprei,bk],bj=bprei,∀l∈[bk+1,bi],bl=bi
证明:
考虑 bprei→bi 之间的赋值情况,一定可以被表示为台阶状。
对于 cnt>bi>cnt<bprei,可以将台阶向上移动到与下一个平齐。
对于 cnt>bi<cnt<bprei,可以将台阶向下移动到与上一个台阶平齐。
Q.E.D
枚举每个区间的 k,即可计算总代价。
具体实现时,给 b 开头加一个极小值,末尾加一个极大值,即 b[0]=−INF,b[n+1]=INF
这样,即可对序列 b 运用上述结论,否则对于 b[1] 极大或 b[n] 极小的情况就会出错。
调试惨烈(
评测记录 - 洛谷
例 1.3:[SCOI2003]字符串折叠 - 洛谷
区间 DP,f[i][j]=min{f[i][k]+f[k+1][j]}
考虑折叠的情况,枚举 j−i+1 的约数,检验是否可以转移即可。
评测记录 - 洛谷
例 1.4:[BalticOI 2008]选举 Easy - 洛谷
此题即为 S−amin≤tot2 ,设 f[i][j] 表示在前 i 个中选择人数和为 j 的党派是否可行。
设计转移方程为 f[i][j]∣=f[i][j−a[i]] (j−a[i]≤tot2) 。事先将 a[i] 排序即可满足题意条件:每次取出的 a[i] 均为最小的。
压掉一维后,时间复杂度为 O(nV) ,空间复杂度为 O(n+V) 。
评测记录 - 洛谷
例 1.5:[SCOI2009]粉刷匠 - 洛谷
设 f[i][j] 表示前 i 块木板,粉刷 j 次的最大正确数,G[i][j][k] 为第 i 块模板前 j 个格子,粉刷 k 次所能达到的最大正确数。
于是 f[i][j]=f[i−1][j−l]+G[i][m][l] ,G[i][j][k]=G[i][j−l][k−1]+Calc(l,j),转移即可。
评测记录 - 洛谷
例 1.6:[CSP-J2020] 方格取数 - 洛谷
设 up[i][j],down[i][j],left[i][j] 分别表示从上,下,左到点 (i,j) 的最大点权。因为只能向右不能向左,于是以列为阶段,转移即可。
评测记录 - 洛谷
例 1.7:[SCOI2007]压缩 - 洛谷
一开始拿到这道题的时候,以为和 [SCOI2003]字符串折叠 - 洛谷 是一样的。但是仔细思考(WA了两发)后发现,其实是不能嵌套的,因为每个 R 只会与离他最近的 M 产生关系。
考虑设 dp[i][j][0] 表示 [i,j] 之间没有 M 的最短压缩长度,dp[i][j][1] 表示 [i,j] 之间有 M 的最短压缩长度。
dp[i][j][0]=min{dp[i][k][0]+j−k} 。
dp[i][j][1]=min{min(dp[i][k][0],dp[i][k][1])+min(dp[k+1][r][0],dp[k+1][r][1])+1}
注意到一个 M 会把原序列分割为互不干扰的两段,于是枚举 M 的出现位置就得到了 dp[i][j][1] 的转移方程。
由于 i−1 位置可以放 M,于是 f[i][j][0] 还可以由 1+f[i][mid][0] 转移得到,iff s[l→mid]=s[mid+1→r] 。
评测记录 - 洛谷
例 1.8:垃圾陷阱 - 洛谷
首先按照时间排序是必须的。
设 f[i][j] 表示在第 i 个选择后,还剩 j 点生命所能达到的最大高度。
有转移 f[i][j]=max(f[i−1][j+delta−duration[i]],t[i−1][j+delta]+height[i])
注意转移边界问题。
评测记录 - 洛谷
例 1.9:[BJOI2019] 排兵布阵 - 洛谷
小清新 DP 题。设 f[i][j] 表示考虑前 i 个城堡,派出 j 的兵力所能产生的最大收益,排序后转移即可。越来越顺手了呢。
写代码记得检查数组开的范围。
评测记录 - 洛谷
例 1.10:不听话的机器人 - 洛谷
设 f[i][x][y][k] 表示考虑前 i 个指令·,目前在 (x,y) 方向为 k 的最少违背多少条指令,转移即可。
实现较为繁琐。
评测记录 - 洛谷
树形 DP
例 2.1:[CTSC1997] 选课 - 洛谷
题意可以抽象为一个森林。
设 f[i][j] 表示在以 i 为根的子树中选出 j 个能得到的最大学分。
不难发现,满足要求的就是一个与 i 相连的连通块。
那么考虑前缀和优化:f[i][j]=max{f[i][k]+f[son][j−k]} 。其中 f[i][j] 表示已经转移的子树的答案。转移边界即为 f[i][1]=val[i] 。为防止后效性,交换一下枚举顺序和方向即可。
评测记录 - 洛谷
例 2.2:ρars/ey - 洛谷
好像考察的是树形背包的上下界优化。不过我不懂,于是由于上下界没卡紧,导致第一次提交 70pts 。
树形背包很好想,设 f[i][j] 表示在以 i 为根的子树内,保留大小为 j 的块的最小代价,转移即可。
每次均为 sz[x]∗sz[y] 的,可以证明复杂度正确。
树上背包的上下界优化 - ouuan的博客
找了篇博客,上面有证明。
至于我为什么假了,可以参见 100pts 评测 - 洛谷 和 70pts 评测 - 洛谷 两次提交。
上下界一定要卡紧,最好采用 f[i+j]=…f[i]+f[j] 这种写法,不容易挂上下界。
写的太丑了,重新放一个:评测记录 - 洛谷
例 2.3:重建道路 - 洛谷
又是一道树形背包,但是我却足足写了两个小时。
时间主要耗费在了写对拍用的暴力上,屡次对拍,挂的却是暴力,侧面反应代码能力不足。
暴力就应该思维清晰,一发冲过。
评测记录 - 洛谷
例 2.4:[ZJOI2007] 时态同步 - 洛谷
将图看成以激发器 S 为根的一棵树。
可以先若在以 S 为根的树中时态同步,则在其任意一棵子树中,时态必定也同步。
考虑树形 DP:设 F(x) 表示使以 x 为根的子树时态同步所需的最小次数,path(x) 表示时态同步时,从 x 到叶子节点的路径长度。
再设 MaxPath 表示未经操作时,x 到叶子节点的最长路径。
容易得出转移方程:F(x)=∑son∈xF(son)+∑son∈xMaxPath−path(son)−edge(x,son)
评测记录 - 洛谷
换根 DP
例 2.5:[POI2008] STA-Station
预处理以 1 为根时的情况,每次转移考虑根节点由父节点变动到子节点带来的影响即可。
评测记录 - 洛谷
例 2.6:[USACO10MAR] Great Cow Gathering G
与上一题相比,这道题带上了点权。转移时多考虑一些东西就行了。
评测记录 - 洛谷
例 2.7:Centroids
树的重心的定义:一个有 n 个节点的树,删去该节点过后,每个连通块的均小于 ⌊n2⌋ 。
原操作其实可以看做子树的移接。
对于此题,以原树的重心为根预处理出子树大小。若一个节点 x 经操作后能成为重心,则考虑除 x 的子树外的所有节点,设最大不超过 ⌊n2⌋ 的子树大小为 S,那么若 n−S−sz[x]≤⌊n2⌋,则 x 能成为根节点,否则不行。
评测记录 - 洛谷
计数 DP
例 3.1:[BJOI2017]机动训练
考虑平方的意义,即:两个人走相同的地形的方案数。
把情况分为 4 类,即(右、上、右上),(左、上、左上)、(右、下、右下)、(左、下、左下)。发现只向单个方向走的情况会重复计算,最后减去即可。
DP 转移顺序难以确定,采用记忆化搜索实现。
评测记录 - 洛谷
例 3.2:Vasya and Array
记 f[i][j] 表示考虑前 i 位,第 i 位为 j 的合法方案数。
设 sf[i]=k∑j=1f[i][j],考虑如下容斥:
f[i][j]=sf[i−1]−sf[i−len]+f[i−len][j]。
sf[i−len] 即令 i−len+1∼i 中的数均为 j ,本来就有不合法的,重复减去的 f[i−len][j](i−len∼i−1 均为 j) 加上即可。
评测记录 - 洛谷
单调队列优化 DP
例 4.1:切蛋糕 - 洛谷
前缀和过后问题就变成了对于每个 i,求 ∀j∈[i−m,i−1] 使得 pre[j] 最大。
于是就变成了一个可以由单调队列维护的问题。
评测记录 - 洛谷
例 4.2:Watching Fireworks is Fun - CF372C
典型的单调队列优化 DP。设 f[i][j] 表示在第 i 个烟花的时候,处于第 j 个位置的最大值。
发现其可以由 f[i−1][k],k∈[j−(d∗Δt),j+(d∗Δt)] 转移而来。
固定长度区间最值,单调队列优化即可。
评测记录 - CF
例 4.3:[POI2014]PTA-Little Bird - 洛谷
朴素 DP 设 f[i] 表示停留在 i 时的最小劳累值。于是 f[i]=minj≥i−k{f[j]+(d[j]≤d[i])}
确定单调队列更新顺序,先 pop,再 query,再 push 即可。
评测记录 - 洛谷
例 4.5:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】