AtCoder DP Practice

众所周知,AtCoder 有一场极 educational 的 DP Contest

A

裸的线性 DP,设 dpi 表示跳到第 i 个格子的最小费用,显然有转移:

dpi=min(dpi1+|hihi1|,dpi2+|hihi2|)

边界为 dp1=0,dp2=|h1h2|

B

裸的线性 DP,设 dpi 表示跳到第 i 个格子的最小费用,显然有转移:

dpi=min1j<idpj+|hihj|

边界为 dp1=0

C

裸的线性 DP,设 fi,0,fi,1,fi,2 分别为第 i 天选择 a,b,c 活动的最大值,显然有转移:

{dpi,0=min(dpi1,1,dpi1,2)+aidpi,1=min(dpi1,0,dpi1,2)+bidpi,2=min(dpi1,0,dpi1,1)+ci

答案为 min(dpn,0,dpn,1,dpn,2)

D

裸的 01 背包,二维太裸了,直接滚动数组。设 dpi 表示处理到当前物品时背包容量为 i 的最大价值,得:

dpj=max(dpj,dpjwi+vi)

注意要从 wwi 枚举才能控制每个物品进入 1 次,否则就是完全背包。

E

传统 01 背包装肯定要爆的,但是注意到虽然 wi 大,但是 vi 小,可以不是很自然地想到交换价值和体积,即设 dpi,j 表示考虑前 i 个物品,达到 j 价值所需的最小体积,得到类似 01 背包的转移:

dpj=max(dpj,dpjvi+wi)

维护总价值,从大到小枚举总价值,找到第一个满足 dpimdp 值输出其 i 即可。

F

暴力 LCS 转移是一个 DP 初心者也可以轻松设计出来的状态,设 dpi,j 表示考虑 s 的前 i 个字符和 t 的前 j 个字符的 LCS 长度,则有转移:

dpi,j={dpi1,j1+1(si=tj)max(dpi,j1,dpi1,j)(sitj)

通过判断转移至 i,j 是否增加来保存最优路径。

G

优美的有向无环图,每个点跑一次 DP,O(n) 解决问题。

H

简单的“数字三角形”类的 DP,设 dpi,j 表示走到 (i,j) 的方案数,显然有转移:

dpi,j=dpi1,j+dpi,j1

corner case 处理可以聪明一点,我们在 dp0,1/dp1,0 设为 1,然后 i=1h,j=1w 遍历直接转移就能少掉边界的讨论。

I

概率 DP,还是那句话,没什么头绪就考虑把答案作为 DP 状态。

dpi,j 表示前 i 个硬币中 j 个正面朝上的概率,转移算算就推出来了(其中 pi 为题目给定的正面朝上的概率):

反面朝上的概率为:

dpi,0=dpi1,0×(1pi)

正面朝上的处理也挺简单:

dpi,j=(dpi1,j1×pi)+(dpi1,j×(1pi))

注意到可以滚掉 1 维,但是没必要。

J

写一次忘一次的期望 DP,可以看看 这个 (doge,当时我怎么写明白的,太牛了

K

一眼的结论:若剩余 0 个石子则当前游戏者必败。

dpi 为剩余 i 个石头时的胜负情况,只要能转移到一个必败状态那就能 win 了,暴力 for 枚举就能做。

L

类似区间 DP,少了断点枚举。设 dpl,r 表示当前游戏方在 l,r 内能取到的最大值,则有转移:

dpl,r=max(lrdpl+1,r,lrdpl,r1)

corner case 显然是 dpi,i=ai。维护前缀和 O(1) 转移即可。

M

前缀和优化,设 dpi,j 表示前 i 个数加起来和为 j 的情况,通过枚举最后一个数显然有转移:

dpi,j=x=0aidpi1,jx

边界为 dp1,j=[jai]

暴力转移显然 T,但是这个东西可以上个前缀和优化:

记:

Si,j=x=0jdpi,j

可以改写转移了:

dpi,j=Si1,jSi1,jai1Si,j=Si,j1+dpi,j

N

只能合并相邻项的石子合并,设 dpi,j 表示合并 aiaj 的最小代价,则有转移:

dpi,j=minikj(dpi,j,dpi,k+p=ijap)

边界就比较常规了,初值为 inf,其中 dpi,i=0

O

状压 DP,考虑能转移的条件:

  1. 当前集合中男女生相容

  2. 当前男女生尚未匹配

dpi,ji 个男生和女生构成的集合 j 的匹配数量,设 Sj 表示集合中已经有的女生情况,显然枚举 i 的过程中需要保证 Sj=i,然后枚举另一个女生满足上述两个条件。写个裸转移:

dpi,j=kj,ai,k=1dpi1,jk

P

Easy 树形 DP。类似没有上司的舞会,设树根为 1,当前节点为 u,设 dpu,0/dpu,1 表示当前节点染白/黑。则根据乘法原理显然有转移:

dpu,0=vu(dpv,0+dpv,1)dpu,1=vudpv,0

Q

是不是挺典的。设 dpi 为前 i 朵花满足“高度单调递增”的情况下权值的最大值,转移为:

dpi=maxj=1i1{dpjhj<hi}+ai

这个裸的是 O(n2) 的,但是上个数据结构比如 Fenwick/Segtree 来查 dp1dpi1max 就能拿下了。

R

我们都会有一个 naive 的第一想法:设 dpi,j,k 表示从 ik 步到 j 的方案数,这个转移非常 easy,但是是 O(n3k)

考虑设 dpi,jk 表示从 ik 步到 j 的方案数,然后我们通过 Floyd 枚举中转点的思路就有转移:

dpi,jk=p=1ndpi,p1×dpp,jk1

然后这个东西是可以上矩乘优化的,答案即为矩阵的 k 次方中所有数的和,复杂度压进了 O(n3logk)

S

数位 DP,套公式:设 dpu,x,lim 表示处理到第 u 位(从右往左),当前前缀 modDx,是否顶上界,记忆化:

int dfs(int u, int x, int lim) {
    if (!u) { return (x == 0); }
    if (~dp[u][x][lim]) { return dp[u][x][lim]; }
    int ret = 0, mx = 9;
    if (lim) { mx = num[u]; }
    for (int i = 0; i <= mx; i++)
        ret = (ret + dfs(u - 1, (x + i) % d, lim && (i == mx))) % P;
    return dp[u][x][lim] = ret;
}

T

第一次一眼秒蓝题。

dpi,j 为前 i 个数填入 1i,以 j 结尾的方案数。注意到对于一个序列的内部排列我们只关心相对顺序,而不是具体的值,在转移过程中,可以将前 i1 个数中 j 的数 +1 保证序列为排列,得到转移:

dpi,j={k=1j1dpi1,k(Si="<")k=ji1dpi1,k(Si=">")

边界为 dp1,1=1,上个前缀和优化一下转移。

U

n16 一眼状压,其实光读题也能猜到是状压了。设 dpi 为集合为 i 时的最大得分,考虑转移即为把集合 i 划分为 2 个子集,然后取其和,转移显然:

dpi=maxji{dpj+dpij}

记忆化搜索处理,枚举个子集。

V

不懂什么叫“换根 DP”,考虑钦定树根为 1,设 fi 为在 i 的子树中选(i 必选)染色,所有点联通的方案数,gi 表示在 i 子树外选点,显然对于点 i 的答案即为 fi×gi,分别给出转移:

fu=usonu(fv+1)gv=gupv,psonu(fp+1)

预处理每个子节点权值的前缀积和后缀积实现,人话就是跑两边 dfs

注:+1 表示有一种只有当前节点染色的方案。

W

套路题,把答案放到区间右端点来统计。设 dpi,j 表示在前 i 个位置中,最后一个 1j 的最大分数,得到转移:

dpi,j={maxk=1i1{dpi1,k}+lkj&rk=iak(i=j)dpi1,j+lkj&rk=iak(ij)

这个空间上可以滚动掉一维,但是时间复杂度还是 O(n2) 的,但是注意到对于 (l,r,a),在 i=r 时,会于 dpli 中产生贡献,这样子问题就转化为了区间加。对于 max 操作显然也是线段树的基本操作之一,对于 dp 数组维护一棵线段树即可。

X

显然是 01 背包,问题在于如何确定一个枚举顺序,也就是各个箱子的优先级。

考虑贪心,有一个技巧叫做 exchange arguments 用于证明贪心,在这个题,显然对于 siwj<sjwi 的情况是要先考虑 i 的,那么交换一下项得到排序依据 si+wi<sj+wj

然后 01 搞。

Y

在没看到 105 的范围之前以为是个傻子题,发现我是傻子。

考虑容斥。在一张没有障碍的地图内从 (1,1)(i,j) 的方案为 (i+j2i1)(从 i+j2 次选择中选择 i1 次向下,其他向右),考虑有障碍的时候就要上容斥了,裸的肯定不行,令 dpi 为从 (1,1)(xi,yi) 障碍,不经过其他障碍的方案数,我们将 (h,w) 设为第 n+1 个障碍就会很舒服,答案即为 dpn+1。然后我们给出转移:

dpi=(xi+yi2xi1)j=1i1dpj×(xixj+yiyjxixj)

这是对的。

Z

斜率优化。裸转移显然:

dpi=min0j<i{dpj+(hihj)2+C}

O(n2) 转移 T 飞。

拆一下式子:

dpi=dpj+hi2+hj22hihj+C=(dpj+hj2)2hihj+(hi2+C)

这个第一个括号只和 j 有关,最后一项是个常数项,抽离出一个一次函数:

θj(x)=dpj+hj22hjx

求解 dpi 相当于求前 i1 的一次函数在平面直角坐标系内经过 x=hi 的最小值,嗯造李超树求解。


ーおわりー

posted @   revkiru  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示