AtCoder Educational DP Contest 做题记录
由于我的一个 dp 是在太差,于是就是在朋友的推荐下过来板刷这场了,之后 Typical DP Contest 也会有的(吧?)
A
题目链接:https://www.luogu.com.cn/problem/AT_dp_a
设 \(f_i\) 表示跳到第 \(i\) 个位置的最小代价,有:
https://atcoder.jp/contests/dp/submissions/70370463
B
题目链接:https://atcoder.jp/contests/dp/tasks/dp_b
依旧设 \(f_{i}\) 表示跳到第 \(i\) 个位置的最小代价,有:
https://atcoder.jp/contests/dp/submissions/70370677
C
题目链接:https://atcoder.jp/contests/dp/tasks/dp_c
为了方便书写,我们不妨设有 \(k\) 个活动(此处 \(k=3\),且从 \(0\) 开始标号),设 \(f_{i,j}\) 表示枚举到第 \(i\) 天,这天选了第 \(j\) 个活动,那么我们有:
时间复杂度 \(O(nk^2)\)。
https://atcoder.jp/contests/dp/submissions/70370863
D
题目链接:https://atcoder.jp/contests/dp/tasks/dp_d
设 \(f_{i,j}\) 表示枚举到第 \(i\) 个物品,已经用了 \(j\) 的容量,我们有:
https://atcoder.jp/contests/dp/submissions/70371181
注意到第一维每次只会需要上一行,而且更新只会需要前面的东西,我们可以把第一维丢掉,第二维从后往前更新。
https://atcoder.jp/contests/dp/submissions/70371193
E
题目链接:https://atcoder.jp/contests/dp/tasks/dp_e
这次 \(W\) 变的很大,但是 \(v_i\) 很小啊!
所以我们考虑设 \(f_{i,j}\) 表示枚举到第 \(i\) 位,价值为 \(j\) 的最小重量,有:
https://atcoder.jp/contests/dp/submissions/70371467
按照 D 的优化思路依旧可以把空间复杂度降下来。
https://atcoder.jp/contests/dp/submissions/70371480
F
题目链接:https://atcoder.jp/contests/dp/tasks/dp_f
设 \(f_{i,j}\) 表示 \(s\) 匹配到第 \(i\) 位,\(t\) 匹配到第 \(j\) 位长度的最大值,有:
题目要求输出方案,记录转移过来的地方就好了。
https://atcoder.jp/contests/dp/submissions/70372181
G
题目链接:https://atcoder.jp/contests/dp/tasks/dp_g
DAG 上 dp。设 \(f_u\) 表示到第 \(u\) 个点的最长路,那么有 \(f_{u}=max(f_{v}+1)\),其中 \(v\) 为指向 \(u\) 的点。那么做个拓扑排序顺便 dp 即可。
https://atcoder.jp/contests/dp/submissions/70372401
H
题目链接:https://atcoder.jp/contests/dp/tasks/dp_h
设 \(f_{i,j}\) 表示 \((1,1)\) 走到 \((i,j)\) 的情况数,则有:
https://atcoder.jp/contests/dp/submissions/70372613
I
题目链接:https://atcoder.jp/contests/dp/tasks/dp_i
设 \(f_{i,j}\) 表示枚举到第 \(i\) 个硬币,向上的次数有 \(j\) 次,则有:
https://atcoder.jp/contests/dp/submissions/70372815
J
开始上难度了(?
题目链接:https://atcoder.jp/contests/dp/tasks/dp_j
首先寿司 \(1/2/3\) 的先后顺序不影响,我们需要记录的东西只有第 \(i\) 个寿司还剩多少个。
设 \(f_{a,b,c,d}\) 表示还剩 \(0/1/2/3\) 个寿司的个数,我们有:
可以这么理解,首先抽一次,然后选到第 \(0/1/2/3\) 个寿司的概率分别是 \(\frac{a}{n}\frac{b}{n}\frac{c}{n}\frac{d}{n}\)。所以转移一下就好。
我们发现式子前面后面都有 \(f_{a,b,c,d}\),貌似不会转移,移项得:
左边系数化为 \(1\),得:
我们发现状态数过多了,想想能省略什么。发现只要知道 \(1/2/3\) 的个数就能算出 \(0\) 的个数,所以把第一维优化掉即可:
时间复杂度 \(O(n^3)\)。
https://atcoder.jp/contests/dp/submissions/70373723
K
题目链接:https://atcoder.jp/contests/dp/tasks/dp_k
涉及到博弈的 dp。我们知道这个题里面没有平局,所以每个状态一定有人必胜,所以我只要有一步操作,使得对方必败,那么我这个状态就是必胜的。
我们不妨设 \(f_{0/1,j}\) 表示先手/后手剩 \(j\) 个石子没取为必胜/必败态,有:
答案即为 \(f_{0,k}\)。
https://atcoder.jp/contests/dp/submissions/70378358
L
题目链接:https://atcoder.jp/contests/dp/tasks/dp_l
区间 dp。令 \(f_{i,j}\) 表示区间 \([i,j]\) 的答案,那么转移显然有,先手操作时:
后手操作时:
答案是 \(f_{1,n}\)。
https://atcoder.jp/contests/dp/submissions/70378598
M
题目链接:https://atcoder.jp/contests/dp/tasks/dp_m
设 \(f_{i,j}\) 表示第 \(i\) 个位置放 \(j\) 个的方案数,显然有 \(f_{0,0}=1\),我们可以写出:
此时时间复杂度 \(O(nk^2)\),考虑优化。
我们发现 \(\sum_{k=0}^{\min(a_i,j)}f_{i-1,j-k}\) 不用遍历,只需要做一个前缀和计算就好了,令 \(sum_{i,j}=\sum_{k=0}^{j}f_{i,k} = sum_{i,j-1}+f_{i,j}\),然后计算即可。
https://atcoder.jp/contests/dp/submissions/70379042
N
题目链接:https://atcoder.jp/contests/dp/tasks/dp_n
设 \(sum_{i}\) 表示 \(\sum_{j=1}^{i}a_j\) \(f_{i,j}\) 表示区间 \([i,j]\) 的答案,那么我们有:
表示枚举断点,然后计算左右区间已经合并的答案,和这次合并要的答案。
注意刚开始 \(f_{i,i}=0\),因为没开始合并。
https://atcoder.jp/contests/dp/submissions/70379464
O
题目链接:https://atcoder.jp/contests/dp/tasks/dp_o
设 \(f_{i,S}\) 表示当前枚举到第 \(i\) 个男生,女生选择的状态为 \(S\),有:
所以说,我们把每个 \(S\) 的 \(1\) 的位置找出来,总共只有 \(O(n2^n)\) 个位置,然后 dp 只有 \(O(n2^n)\) 个状态,转移 \(O(n2^n)\) 次,时间复杂度 \(O(n2^n)\),注意取模不要太多。
https://atcoder.jp/contests/dp/submissions/70379741
P
题目链接:https://atcoder.jp/contests/dp/tasks/dp_p
树形dp,设 \(f_{0/1,u}\) 表示点 \(u\) 的颜色为黑/白时的答案。那么有:
\(v\in u\) 表示 \(v\) 是 \(u\) 的子节点。
https://atcoder.jp/contests/dp/submissions/70379920
Q
题目链接:https://atcoder.jp/contests/dp/tasks/dp_q
设 \(f_i\) 表示以 \(i\) 结尾的答案,那么有:
注意到这个玩意要 \(O(n^2)\),考虑优化。
我们发现我们要查的是所有 \(h_j<h_i\) 的 \(j\) 的 \(f_j\) 的最大值,我们建一颗值域树状数组,求前缀 \(\max\) 即可,时间复杂度 \(O(n\log n)\)。
https://atcoder.jp/contests/dp/submissions/70380014
R
题目链接:https://atcoder.jp/contests/dp/tasks/dp_r
想到 floyd,令 \(f_{x,i,j}\) 表示跑了 \(x\) 步之后的 \(i\) 到 \(j\) 的方案数,我们可以递推出:
所以跑了 \(k\) 步等价于 \({f_{1}}^k\),矩阵快速幂解决即可。
S
题目链接:https://atcoder.jp/contests/dp/submissions/70382692
数位 dp 板子。
令 \(f_{idx,0/1,res}\) 表示当前到第 \(idx\) 位,是否有前导 \(0\),当前数位和 \(\bmod d\)。
令 \(mx\) 为当前位置可以枚举到的最大的数字,那么我们有:
https://atcoder.jp/contests/dp/submissions/70382692
T
题目链接:https://atcoder.jp/contests/dp/tasks/dp_t
神秘的 dp 设计。令 \(f_{i,j}\) 表示长度为 \(i\),填写 \([1,i]\),以 \(j\) 结尾的方案数,对于新加入一个 \(j\),我们可以把原本 \(\ge j\) 的部分全部 \(+1\),这样就是一个排列了。
那么我们有:
\(f_{i,j}=\left\{\begin{matrix} \sum_{k=1}^{j-1} f_{i-1,k} & s_{i-1}=\texttt{"<"}\\ \sum_{k=j}^{i-1} f_{i-1,k} & s_{i-1}=\texttt{">"} \end{matrix}\right.\)
注意到后面是一段区间的和,用前缀和优化即可。
https://atcoder.jp/contests/dp/submissions/70384107
U
题目链接:https://atcoder.jp/contests/dp/tasks/dp_u
首先我们考虑求出每个选择方式的权值,这里复杂度 \(O(n^22^n)\),然后做一个类似背包的东西,使用枚举子集可以做到这部分 \(O(3^n)\)
https://atcoder.jp/contests/dp/submissions/70386668
V
题目链接:https://atcoder.jp/contests/dp/tasks/dp_v
令 \(f_{u}\) 为以 \(1\) 为根时以 \(u\) 为根的子树中的答案,那么有:
那么对于 \(g_u\) 表示以 \(u\) 为根的子树外的答案,那么有:
可是 \(m\) 不一定为质数,有可能没有逆元,所以不妨将式子转换一下,把 \(f_{fa_u}\) 拆开来,变成 \(\prod_{v\in u} (f_{v}+1)\) 的形式,处理前缀积后缀积计算即可。
https://atcoder.jp/contests/dp/submissions/70484050
W
题目链接:https://atcoder.jp/contests/dp/tasks/dp_w
设 \(f_{i,j}\) 表示当前为第 \(i\) 位,上一个填 \(1\) 的位置为 \(j\) 的最大值。首先我们有 \(f_{i,i}=\max_{j=0}^{i-1}f_{i,j}\) 和 \(f_{i,j}=f_{i-1,j}\)。然后我们考虑线段的影响,对于一段线段 \([l_x,r_x]\),我们按照右端点排序,枚举到右端点的时候,我们有 \(f_{i,j}=f_{i-1,j}+\sum_{r_x=i,l_x\le j}a_x\),即加上所有右端点为 \(i\) 且覆盖 \(j\) 的线段进去。
我们发现后面这一大坨可以用线段树优化转移,那么时间复杂度 \(O(n\log n)\)。
https://atcoder.jp/contests/dp/submissions/70492058
X
题目链接:https://atcoder.jp/contests/dp/tasks/dp_x
因为箱子的摆放顺序会影响 dp 答案,我们不妨贪心的去考虑,箱子 \(x,y\),如果 \(x\) 摆在下面,那么有 \(s_x-w_y>s_y-w_x\),即 \(s_x+w_x>s_y+w_y\),所以我们按照 \(w+s\) 从小到大排序之后做一个背包就好了。
https://atcoder.jp/contests/dp/submissions/70492919
Y
题目链接:https://atcoder.jp/contests/dp/tasks/dp_y
快结束了捏。
考虑容斥,首先对于 \((x_1,y_1)\) 走到 \((x_2,y_2)\),答案是 \(\binom{|x_2-x_1|+|y_2-y_1|}{|x_2-x_1|}\)。我们令 \(f_{i}\) 表示从 \((1,1)\) 到第 \((x_i,y_i)\) 不经过障碍的情况数,那么我们有:\(f_i=\binom{x_i+y_i-2}{x_i-1}-\sum_{j=1}^{i-1}f_j\times \binom{|x_i-x_j|+|y_i-y_j|}{|x_i-x_j|}\)。
令第 \(n+1\) 个点为 \((h,w)\),答案即是 \(f_{n+1}\)。
https://atcoder.jp/contests/dp/submissions/70493932
Z
题目链接:https://atcoder.jp/contests/dp/tasks/dp_z
首先显而易见的可以令 \(f_i\) 为到达 \(i\) 的答案,那么显然有:
时间复杂度 \(O(n^2)\),过不了啊/ll
我们考虑拆开来式子,变成:
这个东西我们发现,\({h_i}^2\) 和 \(C\) 都是一定会加上来的,最后考虑。
然后我们发现,\(f_j\) 和 \({h_j}^2\) 都是根据 \(j\) 就可以求出来的,不妨设他为 \(calc(j)=f_j+{h_j}^2\),同时我们把 \(-2h_i\) 看成 \(k\),那么转移式子就变成了一个 \(calc(j)+kh_j\) 的形式,形似一次函数,用李超线段树暴力做即可。
当然我们是为了学习斜率优化 dp 的,所以考虑再推推式子。
我们考虑 \(x<y\) 且 \(y\) 不比 \(x\) 优时是什么情况,那么有 \(calc(x)+kh_x\le calc(y)+kh_y\)。
移项得:\(calc(x)-calc(y)\le k(h_y-h_x)\),即 \(\frac{calc(x)-calc(y)}{h_y-h_x}\le k\)。
将 \(k=-2h_i\) 带入,得:\(\frac{calc(x)-calc(y)}{h_y-h_x}\le -2h_i\),即 \(\frac{calc(x)-calc(y)}{h_x-h_y}\ge 2h_i\)。因为这个玩意神似斜率,我们称之为斜率优化。
我们考虑维护这个斜率 \(k\),假设当前有三个点 \(a,b,c\),有 \(k(a,b)\ge k(b,c)\),那么显然 \(b\) 在直线 \(ac\) 上方,选择 \(b\) 是更裂的。我们用单调队列维护这个东西。由于 \(h\) 单调递增,我们不需要在凸壳上二分,只需要每次弹出最前面的直到满足条件就好啦,时间复杂度 \(O(n)\)。
本文来自博客园,作者:coding_goat_qwq,转载请注明原文链接:https://www.cnblogs.com/CodingGoat/p/19161509

可能会很长,但是尽量在今年 CSP 之前解决吧。
浙公网安备 33010602011771号