【DP】Educational DP Contest

这份 dp 题单的最后几题好难 orz。

前面的题比较简单,所以我会选取一些题来讲,其它的直接看代码理解吧 qwq。

传送门:

https://atcoder.jp/contests/dp

全部 AC 代码:

https://atcoder.jp/contests/dp/submissions?f.Task=&f.LanguageName=&f.Status=AC&f.User=HinanawiTenshi

E

这道题不同于常规的背包问题,因为背包容量很大,我们不能对容量进行 dp,但注意到全部的收益加起来不超过 105,想到用 f(j) 表示收益至少为 j 时的最小容量花费。记当前在第 i 个物品,有状态转移方程:

f(j)=min(f(j),f(jvi)+wi)

J

注意到每碟寿司数量最多 3 个,不难想到用 f(x,y,z) 表示当前有 x 盘寿司数量为 3y 盘寿司数量为 2z 盘寿司数量为 1 时距离吃完全部寿司的期望步数

根据全期望公式,我们有:

f(x,y,z)=(1x+y+zn)f(x,y,z)+xnf(x1,y+1,z)+ynf(x,y1,z+1)+znf(x,y,z1)

根据上述公式进行记忆化搜索即可,细节见代码。

L

注意到 X+Y=sumsum 是总分数),XY=2Xsum,所以 Taro 的目标是最大化 XJiro 的目标是最小化 X

dp(l,r,op) 表示 [l,r] 区间轮到某玩家(op=1 表示轮到 Taro,否则表示轮到 Jiro)决策时 Taro 的最高得分。

op=1 时,dp(l,r,op)=max(dp(l+1,r,0)+wl,dp(l,r1,0)+wr)

op=0 时,dp(l,r,op)=min(dp(l+1,r,0),dp(l,r1,0))

M

f(i,j) 表示前 i 个小孩共分了 j 个蜡烛的方案数,以给第 i 个小孩多少个蜡烛为状态划分依据。

有方程:f(i,j)=k=max(0,jwi)jf(i1,k)

直接转移显然会超时,所以我们在更新 f 的同时维护一个前缀和 ss(i,j)=k=1jf(i,k)

O

f(i,st) 表示前 i 个男人和对应子集为 st 的女人匹配的方案数。

考虑状态转移:

现在已经有 i1 个男人以及相应匹配的子集为 st 的女人集合,当新加入一个男人的时候,对于可以和他配对的女人 j(而且需要满足这个女人不在 st 中),我们有状态转移:(i1,st)(i,stj)

因此有这样的更新 f 的方式:f(i,stj)+=f(i1,st)

R

倍增 Floyd(是之前没听说过的东西呢

g(i,j) 为读入的矩阵,f(k,i,j) 为经过 k 条边,从 ij 的方案数。

那么我们有 f(k,i,j)=u=1nf(k1,i,u)×g(u,j)

如果看不出有什么性质,那我将上面的子换个写法:

fk(i,j)=u=1nfk1(i,u)×g(u,j)

注意到,这正是矩阵乘法的形式!也就是:fk=fk1×g

而且可以发现,g 恰好为 f1,我们有 fk=fk1×f1

所以答案为 f1K=gK,用矩阵快速幂加速这个过程就好了。

S

数位 dp。

f(i,j,k) 表示区间 [1,j99...999¯]j99...999¯i 位,首位为 j ),满足十进制意义下数位和 mod Dk 的数的个数。

  • 对于 j=0f(i,j,k)=f(i1,9,k)
  • 对于 j0f(i,j,k)=f(i,j1,k)+[jk(modD)]+f(i1,9,kj(modD))

T

思路比较新颖的 dp。

f(i,j) 表示对于前 i 个位置,末位值为 j,值域为 [1,i]合法排列数。

合法就是满足题目中所给的大小关系。

考虑从 i1i 的转移、统计:

我们所需要统计的就是 [1,i]{j} 这个值域内有多少个(长度为 i1 的)排列是合法的。

如果 i1,i 需要满足的关系为 < ,那么我们有 f(i,j)=k=1j1f(i1,k),因为在引入 j 后,原先合法的长为 i1,结尾为 k 的排列在 [1,i] 依然是合法的。

类似地,如果 i1,i 需要满足的关系为 >, 有 f(i,j)=k=ji1f(i1,k)

一个直观的理解是,当插入 j 时,[1,i1] 的每个排列中所有 j 的数都加了 1,变换前后的合法方案是一一对应的。

U

f(S) 表示集合 S 按在分组后可以得到的最大贡献。

我们不妨记 U 代表全集,那么答案就是 f(U)

以分出一组 S 的子集 S0 作为划分依据,有状态转移方程 f(S)=max(f(SS0)+cal(S0))

cal(S0) 代表子集 S0 为同一组时的贡献值。

如果在求取每个状态的时候计算 cal,那么时间复杂度为 O(3nn2),无法承受。

所以可以预处理一下所有子集的 cal 值。

这样做的时间复杂度为 O(2nn2+3n)

V

换根 dp。

有点恶心的一题

记点 u 的合法方案数为 f(u)u 只向子树扩展的合法方案数为 f(u)

对于点 u,有 f(u)=(1+f(ch))×(1+f(fa)f(u))

ch 代表 u 的子节点,fa 代表 u 的父节点。

因为给出的数不保证存在逆元,因此需要处理出每个点子节点对应的 f 值的前缀积后缀积

W

个人感觉这道题是这份题单中最难的了 QAQ。

f(i) 表示前 i 个位置做出决策后而且第 i 个决策为 1 所能得到的最大价值。

我们记区间为三元组 (l,r,v),编号为 [1,m]

有转移方程:f(i)=max(f(j)+vk),其中 k 为满足 l(j,i],ri 的区间编号。

我们考虑优化:

对于当前数轴上的位置 i,假设它处于一个 [l,r]区间中,那么我们可以将这个区间的值 v 加到数轴上的 [0,l1] 中,那么在统计的时候,只需要统计数轴[0,i1] 的最大值就可以得到 f(i) 的值了。

位置 i 处于多个区间的情况类似。

然后我们对数轴上的点 i 进行更新。

用什么可以高效维护上述数轴上的操作呢?线段树可以做到,也就是区间加以及区间最大值查询

X

排序 + dp。

考虑从上到下相邻的两个物品 i,i+1 的属性满足怎么样的关系是最优的排列方式。

所谓最优,就是交换这两个物品的相对位置之后,能够承载上面的物品的重量不比原来的位置好。

也就是 min(si,si+1wi)min(si+1,siwi+1)

下面寻找上式的等价条件:

因为 sisiwi+1min(si+1,siwi+1),因此上式等价于:si+1wimin(si+1,siwi+1)

类似地,si+1si+1wi,故上式进一步等价于:si+1wisiwi+1,也就是 si+wisi+1+wi+1

至此,我们找到了排序依据。

事实上,直接用 min(si,si+1wi)min(si+1,siwi+1) 作为排序依据亦可。

剩下的工作变成背包问题。

f(ij) 为前 i 个物品,选取了重量和至多为 j 的物品的最大收益。

有转移方程:f(i,j)=max(f(i1,jwi)+vi,f(i1,j)),然后枚举的 j 的范围是 [wi,wi+si]

与背包问题一样,可以减少一维空间。

Y

组合计数 dp。

直接转移有 n2 个状态,直接去世。

但是障碍很少,所以可以从障碍入手。

我们记 f(x,y) 为从 (1,1) 出发不经过任何一个障碍到达 (x,y) 点的方案数。

那么我们有 f(x,y)=Cx+y2x1CxX+yYxXf(X,Y)​,其中 (X,Y)​ 为障碍点且 X<x,Y<y​。

统计答案和上面的求 f(x,y) 完全一样,把 (n,m) 看成是障碍点即可。

Z

斜率优化 dp。

f(i) 为跳到 i 的最小花费。

显然,转移方程:f(i)=min(f(j)+(hihj)2)+c,其中 j[1,i1]

我们假设决策点为 j,那么有 f(i)=f(j)+hi22hihj+hj2+c

进一步将上式化为:f(j)+hj2=2hihj+f(i)+chi2

我们记 y=f(j)+hj2,k=2hi,x=hj,b=f(i)+chi2

那么这正好为 y=kx+b 的形式。

我们的目标是最小化 f(i),这等价于最小化 b,也就是从维护的下凸壳中找到使直线的 b 最小的点即可。

对斜率优化不熟悉可以看看这个:https://www.cnblogs.com/Tenshi/p/14481908.html

posted @   HinanawiTenshi  阅读(267)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示