DP Problems

考虑到 Topcoder AC 不方便,所以 Topcoder 的都没写()

1.CF1152F2 Neko Rules the Catniverse (Large Version)

题意: 给定 n,k,m,求满足条件整数序列 a1,a2,a3,,ak 个数:

  1. 1ain

  2. i2,aiai1+m

  3. ai 互不相同。

n109,k12,m5

思路:

我们发现,三个条件中最难的是 ai 互不相同,这意味着我们如果按照 a1,a2,,ak 顺序 dp 将极其困难。

所以我们考虑按照值域的顺序来 dp,这里常见的计数就是插入的方法。

我们从大到小考虑,每次假设插入当前这个数,对于一个序列,我们可以插入在末尾或者某个数前面。

考虑到这个数是当前最小的,末尾肯定可以。

而如果在某个数后面就需要后面的数满足 m+ 当前这个数。

所以我们不妨设 f(i,j,S) 表示考虑到 [i,n],已经有了 j 个数,并且 [i+1,i+m] 这个范围内的情况是 S,每次转移乘上 popcount(S)+1 即可。

然后发现这个可以用矩阵加速转移。就做完了。

提交记录

2.GYM100377H Petya and arrays 加强版

题意: 求满足以下条件的 n 长度整数数组:

  1. 每个数都属于 {1,2,3,,P}/{A}

  2. 连续的子数组的和不是 P 的倍数。

109+7 取模。

n85,A,P109

思路:

首先第二个性质的形式显然是将数组转化成前缀和。意味着不存在 sisj(modP)

所以我们不妨将前缀和对 P 取模。现在就是不能有相等的。

同时我们还发现要求不能有 si+Asi+1(modP)

我们不妨将所有的 ii+A(modp) 连边,这样会形成若干个环。

现在变成了我们需要按顺序在这些环上选取一些数,要求有相邻的不能相邻的选。

我们不妨对每个环 dp 算出在这个环选若干个组成序列的方案数。

考虑到 n 很小,我们还是可以以插入的形式,不妨设 f(i,j,S) 表示当前在环上按顺序考虑了 i 个点,已经选了 j 个,第一个元素和 i1 的状态是 S

转移很好转移,同样可以矩阵快速幂优化,算答案时看一下 S 即可。

考虑到所有环都是相同的,我们只用计算 n 个环的贡献即可。这里可以用背包,最后容斥和组合数算一下即可。

(不保证正确性)

3.Topcoder10741 Colorful Maze

题意:

有一个 n×m 迷宫,包括障碍物和空格,其中空格都有一个颜色 06

每种颜色有概率 ai 是危险的。如果进入一个危险颜色的格子两次就会死亡。

现在给定起点和终点和地图,求最优策略下活着走到终点的最大概率。

n,m50

思路:

显然最优策略不是固定的,于是我们考虑设计 dp 状态。

对于这种概率 dp,更好的方式是从起点往回推。

f(i,j,mask,D) 表示从 (i,j) 出发,已经确认了 mask 是安全的,D 是危险的(如果没有则 D=7),求走到终点的最大概率。

我们枚举走到的下一个格子转移即可。

但是问题在于如果我们走到一个 mask 中的格子就将陷入死循环。

为此我们需要将所有相同颜色的格子所称一个大点来 dp 即可。

4.P2150 [NOI2015] 寿司晚宴

题意:

选取两个集合 A,B 满足:

  1. A,B{2,3,,n}

  2. 不存在 x,y 使得 xA,yBxy 不互质。

n500

思路:

经典题。

我们考虑将 A,B 的质因子集合记作 PA,PB,不难发现 PAPB=

但是质数的个数太多了,不好 dp。

我们发现,如果将质数按照 n>n 分类,则每个数至多含有一个二类质数!

而枚举一下发现一类质数个数最多 8 个。

所以我们可以把每个数划到其二类质数的那一类,现在问题转化为:每一类只能一个集合选,且一类质数不冲突。

于是我们对一类质数状压即可。时间复杂度 O(n216)

提交记录

5.UOJ86 mx的组合数

题意:

对于 i=0,1,,p1,分别求 lxr(xn)i(modp) 的个数,对 998244353 取模。

p30000,l,r,n1030

思路:

Lucas 定理非常厉害的应用。对于模数很小的情况 Lucas 定理会很有用。

我们考虑 Lucas 定理的等价形式:不妨设 x=(x1x2xm)p,n=(n1n2nm)p,则:

(xn)(x1n1)(x2n2)(xmnm)modp

然后明显这道题就变成了一个数位 dp 题。

我们不妨设 f(i,j,0/1) 表示当前考虑了前 i 位,组合数乘起来模 pj,是否贴着上界。

转移需要枚举下一位的所有选择,时间复杂度为 O(p2logn)。但是显然是过不去的。

我们发现如果我们把乘法转换成原根的加法,这将是一个卷积的形式,并且模数 998244353 支持 NTT,所以用 NTT 优化即可做到 O(plogplogn) 了。

但是我们无法计算 0 的方案数,但是我们也只无法计算 0 的方案数,最后用总数减去即可。

注意差分的时候如果 l1<n 也要减去 0 的贡献。

提交记录

6.POJ1090 Chain

题意:

现在有一个长为 n 的 01 串,每次可以执行下面两种操作之一:

  1. 找到最右边的 1 并反转其左边的元素。

  2. 反转最后一位。

求最少几次变成 0。

思路:

首先我们需要观察:连续两次同种操作会抵消,所以操作一定是交替进行的。

所以只有两种可能,并且我们发现每种操作都会减少或增加一个 1,所以这其实就是格雷码!

我们知道,第 n 个的格雷码是 n[n2],所以我们可以倒退出其是第几个格雷码。

注意到标准格雷码是一个环,有两种方法到起点,都要考虑。

7.Topcoder13457 BoardFolding

题意:

有一个 n×m 的 01 矩阵,可以横着或竖着对折,要求重叠部分完全一样,求最后能折成的最小面积。

n,m250(实际可以做到 O(nm)

思路:

一个很自然的想法是 f(a,b,c,d) 表示 [a,b]×[c,d] 这个矩形是否可行。

转移枚举一下对折线即可,时间复杂度 O(n2m2(n+m))

我们考虑优化,通过观察,我们发现一个事情:横着对折和竖着对折互不影响。

所以我们可以分成 f(a,b)f(c,d),表示只考虑一种方向的对折是否可行,最后乘起来即可。

进一步,我们可以直接变成 f(a)f(b) 表示 [1,a] 是否可行和 [b,n] 是否可行,然后乘起来。

用 Manacher 来转移,时间复杂度 O(nm)

8.CF111C Petya and Spiders

题意:

有一个 n×m 的矩阵,每个格子有一只蜘蛛,每只蜘蛛可以往上下左右移动一格或者不移动,求最多空出多少个格子。

n×m40

思路:

根号分治得到 min{n,m}6,所以我们可以状压 dp。

f(i,j,k) 表示到第 i 行的都确定了,当前第 i 行和第 i+1 行的状态是 j,k

如果直接枚举第 i+1 行的话需要枚举 (x,y,z),转移如下:

f(i,j,k)+popcount(x&(~j))+popcount(k&(~y))+popcount(z)f(i+1,k|y,z)

但是时间复杂度是 O(n230),显然不行。

发现 x 其实不会关心转移,所以我们对 (j,y,z) 记录最小的 x 即可。

时间复杂度 O(n224)

提交记录

9.[AGC012E] Camel and Oases

题意:

直线上有 n 个点 x1xn 和一个数字 V,两个点可达当且仅当其距离小于等于 V

从一个点出发,可以到达其所有直接或间接可达的点,或者跳跃到任何一个点,但是这样的话就会使得 V[V2]

求每个点出发能否访问所有点。

n,V2×105

思路:

显然 V 的取值总共有 k=[log2V] 个,我们就是要把这些点分成 V 组,使得每组互相可达的最小的 V 不超过分配给这个组的长度。

所以我们考虑状压 dp,不妨设 f(S) 表示如果用 S 中的长度,最长能覆盖的前缀。g(S) 则表示后缀。

我们通过枚举下一个长度和预处理可以计算出这两个值。

然后我们发现对于一个点,假设其最近不能覆盖到的是 lr,则我们需要找到 S 满足 f(S)l,g(S)r,这显然是充分的。

于是二维数点即可。

时间复杂度 O(nlogn)

提交记录

10.CF678E Another Sith Tournament

题意:

n 个人决斗,你知道每两个人之间彼此获胜的概率,你先选两个人决斗,赢的人继续和你再次选的人决斗(你可以根据上次结果来选),求最后 1 号获胜的最大概率。

n18

思路:

首先这是一道概率问题,我们发现,如果我们知道了当前的人是 i,现在还未决斗的人的集合是 S,那么我们应该有一个最优策略是的我们会选一个 ji 决斗。

所以我们不妨设 g(i,S) 表示最大的概率,那么我们现在要做的就是选一个 j,使得决斗后的概率最大。

明显有 g(i,S)=maxj{g(i,S{j}),g(j,S{i})},则我们最后只用看最开始选哪个人即可。

时间复杂度是 O(n22n),关键在于什么状态会确定最优策略。

提交记录

11.CF1342F Make It Ascending

题意:

[n] 划分成 S1,S2,,Sk,设 f(S)=iSai,要求 f(S1)<f(S2)<<f(Sk) 且存在 ijSj 使得 i1<i2<<ik

n15

思路:

显然是用状压 dp,我们思考一下哪些东西会影响状态:当前已经选了的元素,总共选了多少个集合,上一个的代表,上一个集合的权值。

只要知道这些就能转移,但是显然不能都存下来,我们发现题目特征是单调递增的序列,这让我们想到 LIS 的二分算法,所以我们可以记 f(i,j,S) 表示选了 i 个集合,上一个代表是 j,用了 S 中的元素,上一个集合权值和最小是多少。

我们发现转移只用枚举下一个集合是什么即可。注意需要取前缀 min 来优化,时间复杂度 O(n23n)

但是这道题比较卡常,需要用刷表法,当遇到不可行的状态时就不去转移。

提交记录

12.P2466 [SDOI2008] Sue 的小球

题意:

一个平面上有若干个小球从开始时刻以固定的速度开始下落,给定起点,从起点出发在 x 轴上移动,移动 1 格花费 1 秒。

每次第一次到达某个横坐标时,就能获得现在这个横坐标的所有小球的纵坐标的值的和,求收集完所有小球后贡献最大是多少。

n1000

思路:

首先,这道题最开始需要观察,我们发现,如果从起点出发,向左走了一段距离后向右走,那么我们肯定要走到越过原来起点的位置,这样才会有新的收益。所以我们就能大概知道答案的样子。

但是这个计算方式也需要转化一下,我们发现,当我们走了 1 秒后,我们对答案的贡献其实是当前没有走到过的小球的速度和。

所以任何时刻收集的小球都是区间,我们考虑区间 DP,设 f(l,r,0/1) 表示走完 [l,r] 区间后,最后一次是 lr 或者 rl

如果直接枚举上一次不同方向的话就是 O(n3) 的了,过不去。我们发现其实 f(l,r,0) 可以从 f(l,r1,0)f(l,r1,1) 转移就够了,这样就能涵盖所有的情况。

所以我们便得到了 O(n2) 的做法。

提交记录

13.CODE FESTIVAL 2017 qual B D-101 to 010

题意:

有一个 01 序列,每次可以将一个 101 变成 010,求最多能操作几次。

n5×105

思路:

题解直接线性 dp 什么神仙。感觉我的做法更平易近人一点。

我们首先还是观察,我们发现其实我们可以将整个段按照中间隔了超过 1 个 0 的分成若干段,每一段都是 11011011011 这样的。

我们先对于两个 0 的 10111101,我们发现让其中的一个 101 占用中间的所有 1 与两个都占一点是一样的。

所以我们可以根据这个对于每一段来 dp,设 f(i,0/1/2) 表示第 i0 占用左边的 1/右边的 1/不用。

转移非常简单,于是我们直接分段也是在 O(n) 内解决这个问题。

提交记录

14.ZOJ1234-Chopsticks

题意:

n 个数分成 K 个三元组 abc,每个三元组权值是 (ab)2,求最小权值和。

n5000

思路:

首先不难猜测最优解的所有 a,b 都是相邻的,否则我们可以通过调整使得最优解不优。

所以我们就可以考虑 dp,倒序排序,设 f(i,j) 表示前 i 个选了 j 个的最小代价,如果 3ji,就用 a=i,b=i1 转移即可。

注意这道题卡空间,需要滚动数组。

提交记录

15.[ARC078F] Mole and Abandoned Mine

题意:

给定一张无向连通图,边有边权,求最少割掉的边权总和,使得 1n 只有唯一一条简单路径。

n15

思路:

O(n23n) 的更劣做法。

我们首先需要观察最终剩下的样子,不难发现其实是将 [n] 划分成若干个集合,路径上每一个点都在一个集合中,集合之间除了路径上的边没有其他边。

这就很好 dp 了,f(i,S) 表示现在路径上最后一个点是 i,已经用了 S 中的点。

我们只需要枚举下一个路径上的店和其对应集合即可。需要预处理两个点集的所有边权,这个可以 O(n23n) 暴力处理,但是更好的方法是算出一个点集内部的边权然后容斥,这样变成 O(n22n)

于是总的复杂度是 O(n23n),可以用链表储存每个集合的元素,这样可以减少常数。

但是我们其实可以将选点和选集和分开,这样就是 O(n3n) 的了。

提交记录

16.CF55D Beautiful numbers

题意:

[l,r] 中所有被其每个位置上的非零数整除的数的个数。

l,r9×1018,T10

思路:

最朴素的想法是记录当前存在的数字集合与 29 每个数字的余数,但是显然过不去。

首先,我们发现,只用知道 5,7,8,9 的余数就可以推出所有数是否整除,所以我们只用记录这四个书的余数。

其次,我们发现,我们其实只需要记录当前数字集合中 2,3,5,7 的最高次幂即可,所以我们总的状态数是 18×2520×48=2×106,完全可做。

注意到是多测,所以我们记忆化搜索时不记录 lim 的记忆化。

提交记录

17.Topcoder 修正表达式

题意:

现在有三个正整数 a,b,c,可以执行一下操作任意多次:

  1. 09 中的一个插入到某个数的某个位置,单次花费 I 元。

  2. 将某个数的某个位置修改,单次花费 R 元。

  3. 删除某个数的某个位置,单次花费 D 元。

现在给定 a,b,c,I,D,R,求使得 a+b=c 的最少花费,要求任意时刻都没有前导 0

思路:

我们考虑数位 dp,设 f(z,carry,A,B,C,S,lim)

z=0/1/2 表示当前处理哪个数。

carry 表示当前的 cab 也就是进位。

A,B,C 分别表示当前应该处理到这三个数的哪一位。

S=07 表示当前三个数是否有前导 0。

lim 表示当前执行的插入次数,以此来断绝后效性。

我们从 z=2 开始,然后 z=1,然后 z=0 轮流进行。

首先考虑终止状态,如果 z=2 (注意这个一定要有,否则有可能出现 100,100,10000 这种最后一个 0 被忽略的情况)并且 A=B=C=0 并且 carry=0 的话就是一个可能的终止状态。

否则,我们考虑转移。

首先,如果我们保留不变,则当前的 z 这个数处理减去 1,并且需要更新前导 0 和进位,同时要确保这个数不是前导 0

如果我们插入,我们枚举插入的这个数,依然要求没有前导 0,同时更新 lim

如果是修改,我们枚举修改成什么,然后更新即可。

如果是删除,需要注意,对于 a,b,我们可以直接 A1B1 进行删除。但是假设当前我们还是前导 0,我们也可以不放数,不进行任何操作,转移到下一个数即可。

最后对于 c 的情况,如果存在某个时刻 C=0,A0,B0,则我们需要处理看看如果当前把 A,B 删了也是一种情况。

总之转移就是这些,代码用记忆化搜索还是相对比较好实现的。

提交记录

18.CF1334F Strange Function

题意:

定义 f(a) 表示 a 的前缀最大值构成的数组,给定 a,b,以及每个 a 中的数删除的代价,求最小代价使得 f(a)=b

n5×105

思路:

先考虑朴素的 dp,设 f(i) 表示 1i 的最小代价,b 中位置 t 可以唯一确定。则:

f(i)=max0j<i,aj=bt1{f(j)+k=j+1i1[akaj][pk>0]pk}+pi

我们考虑维护所有下标并 lazy 更新。

我们发现 ii+1 时,如果 pi>0,则比 ai 大的都会更新,而本身还要考虑被 i 更新。

需要后缀加,单点查询,单点修改,用 BIT 维护即可。

提交记录

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