动态规划题目选讲

\(\text{动态规划题目选讲}\)

\(\text{zph}\)

\(\text{长沙 2025.5.7}\)

based on 2025 年湖南省队集训《dp 专题》。

\(16\) 题是正式的讲课内容,本文会持续更新。

引入

动态规划(dp)是算法竞赛的一个热门考点。本文选取了约 \(10\) 道 dp 好题,旨在帮助大家掌握常见的 trick,同时启发大家思考,拓宽思维。

为了达到更好的学习效果,在此进行如下约定:

  1. 当你知道关于题目的信息后,题目难度和学习效果可能会降低,这一点相信大家深有体会。故本文中不保证题目按任何逻辑顺序排列。
  2. 每个题目的解法会分步给出,请各位阅读每一步后,在前文基础上进行至少 \(10\) 分钟的独立思考。
  3. 本文侧重点在于 dp 的状态设计和转移优化,具体的代码实现细节将略过。

方法论

  1. dp 状态的设计在于简洁。你需要对状态进行充分的描述(避免后效性),在此基础上,你应该用尽可能少的维度描述状态。为了减少维度,你需要对问题的性质进行挖掘,合并同类的状态,或剪去无用的状态。通俗的说,我们只关心我们需要关心的事物。
  2. 如何优化转移?一种方法是剪去无用的转移,另一种方法是将转移写成便于维护的形式,有时需要套用已有的模型求解。

举个例子,对于经典的 \(01\) 背包问题:

设计状态 \(dp(i,j)\) 表示,前 \(i\) 个物品用了 \(j\) 的体积所能达到的最大价值。状态设计的原因是,我们只关心用了多少的体积(即 \(j\))和最多装了多少价值(即 \(dp\) 值),这些体积具体装了啥,我们并不关心。

考虑经典的转移优化,我们发现 \(dp(i+1,j)\) 只依赖于 \(dp(i,0),dp(i,1),\cdots,dp(i,j)\),这是一个非常好看的形式,因为若在一轮转移中对 \(j\) 倒序处理,我们可以把整个数组压成一维。

扩展阅读资料

https://www.luogu.com/article/ki71nw88

https://www.cnblogs.com/Mackerel-Pike/p/16395436.html

目录

此处列出本文中的所有题目,各位可以提前思考。

  1. Heat Stroke (https://qoj.ac/problem/8811)
  2. 棋盘染色 (https://loj.ac/p/6385)
  3. 麻将*
  4. Paired Roads (https://codeforces.com/gym/104922/problem/I)
  5. Dance (https://qoj.ac/problem/6372)
  6. Sequence Transformation (https://codeforces.com/problemset/problem/280/E)
  7. Famous in Russia* (https://atcoder.jp/contests/xmascon20/tasks/xmascon20_f )
  8. Investors (https://qoj.ac/problem/5507)
  9. Complexity (https://atcoder.jp/contests/agc033/tasks/agc033_d)
  10. Array Covering (https://codeforces.com/problemset/problem/720/F)
  11. City United (https://qoj.ac/problem/7303)
  12. Desant 3 (https://loj.ac/p/4134)
  13. Broken Dream (https://acm.hdu.edu.cn/showproblem.php?pid=7374)
  14. Random IS (https://atcoder.jp/contests/arc108/tasks/arc108_e)
  15. 芒果冰加了空气 (https://qoj.ac/contest/1081/problem/5357)
  16. Zigzag (https://atcoder.jp/contests/agc017/tasks/agc017_f)

*:一些题目没有中文或英文题面,在此列出:

  1. 给一套有三种花色(万筒条,下文中记为 m p s),每种花色有 \(n\) 种点数,每个点数 \(4\) 张,共 \(12n\) 张的麻将,给 \(13\) 张起手牌,剩下的 \(12n-13\) 张牌均匀打乱,即 \((12n-13)!\) 种可能等概率随机出现,问期望的最早胡牌巡目数,对 \(998244353\) 取模(不考虑七对),\(n \le 40\)

  2. 你经营了一家会员制餐厅,今天有 \(N\) 个客户,每个客户想吃的菜需要 \(A_1,A_2,\cdots,A_N\) 的时间制作,每个客户吃菜的时间为 \(B_1,B_2,\cdots,B_N\)

    你的餐厅还蛮大的,所以多个客户可以同时吃菜。

    对于序列 \(A,B\),和一个正整数 \(k(1 \le k \le N)\),定义 \(f(A,B,k)\) 为:以任意顺序服务任意 \(k\) 个客户,所需要的最少时间。需要的时间被定义为从开始制作第一个客户想吃的菜,到最后一个客户吃完,所经过的时间

    给定 \(N,V,B\),对于所有 \(k\),求满足 \(1 \le A_i \le V\) 的总共 \(V^{N}\)\(A\)\(f(A,B,k)\) 之和,对 \(998244353\) 取模。

    \(1 \le N \le 30,1 \le V \le 20, 1 \le B_i \le NV\)

A. Heat Stroke

Step 1:

\(N,L\) 同阶。

对于道路 \(i\),考察这条道路上所有人的决策,令 < 表示往左走,> 表示往右走,x 表示离开,则决策一定形如:<<...<< >>...>> xx...xx 或者 >>...>> <<...<< xx...xx

x 是一段后缀很好理解,不然会有一个 x 的时刻,左右至少有一个没满员,与题意矛盾。

<<...<< >>...>> 这种结构也很好理解,考虑 exchange arguments:如果有决策形如 <<><>,则交换第二个和第三个,变成 <<<>>,交换后你会发现左右两边被塞满的时刻不会变晚。

Step 2:

有了这个性质后,我们就可以 dp 了,令 \(dp(i,<,>,\text{x},0/1)\) 表示,考虑了前 \(i\) 条道路,第 \(i\) 条道路上 < > x 分别有对应的个数,< > 哪个在前面,且从前 \(i-1\) 条道路上飞走时左右两边均已塞满,从第 \(i\) 条道路上飞走时左边已塞满。

你可以理解为,在决策第 \(i\) 条道路时,需要满足第 \(i-1\) 条道路对右边的要求,和第 \(i\) 条道路对左边的要求。

进一步的,\(<,>,\text{x}\) 只需要记录其中之二,因为另一个能通过总数唯一确定。故状态数降到了 \(O(N^2)\)

Step 3:

考虑转移,转移需要保证第 \(i-1\) 条道路的人飞走之前,右边会被塞满,所以新的 \(<\) 就被确定了,故只需要枚举一维即可转移(注意特判 \(\text{x}=0\) 的情况)。

这样就得到了时间复杂度 \(O(N^3)\) 的做法。

Step 4:

把这个做法实现出来,你会惊奇的发现转移是对一个二维数组的一条斜线取 max(如果选了 \(<,>,\text{x}\) 中不同的东西保留,这里可能会是横线或者竖线),仔细分析你写的每一句话,你还会发现左右端点都递增,可以单调队列维护。

复杂度 \(O(N^2)\)

B. 棋盘染色

Step 1:

\(m\) 很小,考虑对 \(m\) 这一维状压。

一个思想是进行轮廓线 dp,也就是说你可以在一行中一个一个填,以替代枚举一行中总共 \(2^m\) 种情况。

Step 2:

你需要记录轮廓线上的如下信息:

  • 每个位置是黑色和白色。
  • 同色之间的联通情况(贝尔数)。

Step 3:

你可以采用如下剪枝策略:

  • 一个显然的剪枝是钦定相邻两个同色位置在同一个连通块,加上后搜出来状态数只有 \(3 \times 10^4\) 左右。
  • 还有一个剪枝就是如果存在 \((a,b,c,d)\) 满足 \(a \lt b \lt c \lt d\)\(a,c\) 同色不同块,\(b,d\) 同色不同块,也可以剪枝。

转移的时候,可以对于每一种轮廓线,预处理出在 \(m\) 个位置放哪种颜色会转移到哪种轮廓线,可以建出一个自动机,直接在这个自动机上进行 dp 就行,复杂度视搜出来的状态数而定。

注意特殊处理轮廓线上的拐点。

C. 麻将

Step 1:

先考虑如何判断是否胡牌。

不妨假设只有一种花色,令其为 m

\(dp(i,j,k,0/1)\) 表示,考虑前 \(i\) 种点数 1mim,组成了 \(j\)(i-1)m,im 的两面搭子(为了凑成 (i-1)m,im,(i+1)m),有 \(k\)im 的孤张(为了凑成 im,(i+1)m,(i+2)m),是否有对子。在此情况下所组成的最大面子数。

Step 2:

转移枚举:新的点数是否自己组雀头,是否自己组成刻字,和前面连上的顺子数,和前面连上的两面搭子数,孤张张数。注意到 \(j,k \le 2\),因为三个同样的顺子可以组成三个刻子,是等价的。

对于多种花色,令 1p = (n+2)m1s=(2n+3)m 即可(中间用一个空位隔开)。

Step 3:

对于上面的 dp 建立自动机,一个状态用 \(3 \times 3 \times 2 = 18\) 个数表示,一个状态有 \(5\) 个后继状态,对应后面加入的一张牌的张数 \(\in [0,4]\)

进行一个基本的期望意义的转化:对于所有 \(i\),求按点数从小到大依次选 \(i\) 张胡不了的方案数 \(cnt(i)\),答案就是 \(\dfrac{\sum_{i} cnt(i)i!(12n-13-i)!}{(12n-13)!}\)

Step 4:

\(f(x,len,u)\) 表示考虑点数 \([1,x]\),一共选了 \(len\) 张牌,走到自动机上的点 \(u\) 的方案数。对于 (n+1)m,(2n+2)m 需要特殊处理,钦定必须有 \(0\) 张即可。

复杂度 \(O(Kn^2)\)\(K\) 是自动机点数,正常实现的话可能在 \(1000\) 左右,跑一个最小化自动机大概在 \(200\) 多。

注:如果你记不得如何写最小化自动机,可以尝试如下乱搞算法:

  • 在自动机上直接删去起点到不了的状态,和到不了终点的状态(适用于 B 题)。
  • 在自动机上暴力跑若干步,如果发现两个状态的所有长度的路径条数全部相同,可以合并(适用于 C 题)。
  • 枚举任意两个状态,合并后进行对拍(适用于 C 题)。

第一条显然正确,第二条和第三条未经任何验证,只是一些非常符合直觉的东西。

D. Paired Roads

Step 1:

能感受到凸性。

感性理解:我们会优先选择权值大的东西。

Step 2:

考虑树上 dp,\(dp(u,0/1,0/1)\) 表示 \(u\) 的子树里面选,\(u\)\(u\) 的儿子的边选了奇数还是偶数条(这对应了 \(u\)\(u\) 父亲的边是否需要选),是否把 \(c_u\) 加到了代价里面。这个 dp 是线性的,套一层 wqs 二分问题就能解决。

Step 3:

构造方案比较麻烦,但是一个问题是凸的,大概率它的子问题也是凸的。

对于一个凸包,一条直线切上去一定会切一个区间。对每个 dp 状态记录最优值,和可能取到的最小的数量和最大的数量(记录双关键字)。

Step 4:

还原方案时,考虑一个一个把子树拆下去(dp 的逆过程),拆下去的部分有一个可以取到的区间,剩余的部分也有一个可以取到的区间,在里面任取两个数,只要加起来符合条件,就可以往下递归。

复杂度 \(O(n \log A)\)

E. Dance

Step 1:

将所有点预先往左边平移 \(d\),则问题等价于,所有点留在原位或向右移动 \(2d\) 个长度,为方便起见下文中用 \(d\) 表示 \(2d\)

考虑将 \(x\) 轴上的所有点排列成一个矩阵:

1 d+1 2d+1 .... 
2 d+2 2d+2 ....
.  .    .  ....
.  .    .  ....
.  .    .  ....
d  2d  3d  ....

你能做的操作是,把一些点往右挪一个位置,每一行的末尾需要特殊处理。

Step 2:

观察到这个矩形一定有一维 \(\le O(\sqrt{n})\),可以分 \(d\) 小和 \(d\) 大讨论。

对于 \(d\) 小,可以设 \(dp(i,mask,0/1)\) 表示,当前在数轴上从左往后扫了前 \(i\) 个位置,前 \(i\) 个位置中的所有点均已被覆盖,\([i+1,i+d]\)\(mask\) 的位置被移动后的点占据,最后一个 \(0/1\) 表示是否有一个未确定右端点的区间跨过 \(i\)

换句话说,\(dp(*,*,0)+a\) 可以转移到 \(dp(*,*,1)\),表示新开一个区间;\(dp(i,*,1)+b\) 可以转移到 \(dp(i+1,*,1)\),表示将当前区间延长 \(1\)\(dp(*,*,1)\) 可以转移到 \(dp(*,*,0)\),表示结束一个区间,

Step 3:

对于 \(d\) 大,设 \(dp(x,y,mask,0/1)\) 表示,按 \(1,d+1,2d+1,...,2,d+2,2d+2,...\) 的顺序扫描到了 \((x,y)\),当前轮廓线上(第 \(x\) 行的前 \(y\) 个,和第 \(x-1\) 行中的第 \(y+1\) 列后面的)被区间覆盖的状态是 \(mask\)\((x,y)\) 上的点是否被移到了右边。

注意特殊处理每一行每一列的最后一个位置。

F. Sequence Transformation

Step 1:

回忆 Slope Trick,这个东西实际上是在维护实数轴上的分段函数。

Step 2:

\(f_i(x)\) 表示,填了 \([1,i]\)\(y_i\) 填的是 \(x\) 的最小代价,转移:\(f_i(x)=(x-x_i)^2+\min_{y \in [x-b,x-a]} f_{i-1}(y)\)

\(f_1(x)\) 的图像很简单,就是抛物线 \(y=(x-x_1)^2\)\(f_2(x)\) 的图像可以看做将 \(f_1(x)\) 的图像平移,从最低点切开,将右边的部分再平移,中间用一个平台相连,然后整体加上 \((x-x_2)^2\)

\(f_i(x)\) 的图像我们可以看做 \(O(i)\) 段开口向上的抛物线拼接成的下凸函数(可归纳证明),利用类似 slope trick 的方法分段维护转移,暴力的复杂度是 \(O(n^2)\),用平衡树可以做到 \(O(n \log n)\)

G. Famous in Russia

Step 1:

先考虑选好 \(k\) 个人的情况:

假设有两个人,制作时间是 \(a_1,a_2\),吃饭时间是 \(b_1,b_2\),且 \(b_1 \lt b_2\)。如果先服务 \(1\) 再服务 \(2\),时间为 \(\max\{a_1+b_1,a_1+a_2+b_2\}\),如果先服务 \(2\) 再服务 \(1\),时间为 \(\max\{a_2+b_2,a_1+a_2+b_1\}\),由于 \(b_1 \lt b_2\),所以 \(a_1+a_2+b_1,a_2+b_2 \lt a_1+a_2+b_2\),所以先服务 \(2\) 更优,即按 \(b\) 降序排列的顺序服务是最优的。

Step 2:

反过来考虑这个过程,你先假设所有人吃完之后同时离店,也就是说,你有 \(k\) 条线段,一开始长这样:

G_image1

你可以做的是,将一些红的段往右边挪,使得任意两个红段不交,你需要最小化移动后整个图形的宽度。贪心的,你肯定是先满足 \(1\),再满足 \(2\),然后满足 \(3\)

形式化的刻画这个贪心:一开始有一个变量 \(t=0\),依次考虑 \(i=1,2,\cdots,k\),执行 \(t \leftarrow \max\{t,b_i\}\)\(t \leftarrow t+a_i\)

Step 3:

考虑还没确定具体是哪 \(k\) 个人的情况,依然可以贪心的考虑:

维护优先队列 \(Q\) 存储服务每个人所需的时间代价,显然小的元素在堆顶。另外维护变量 \(ans\) 表示答案,初始为 \(0\)。将时间轴在 \(b_1,b_2,\cdots,b_n\) 处分段,然后依次考虑 \(i=1,2,\cdots,n\)

  • \(ans+Q.top \le b_i\),因为在这一轮结束后 \(ans\) 一定会对 \(b_i\)\(\max\),这个人不选白不选。将 \(ans\) 加上 \(Q.top\),然后移除堆顶。
  • 否则,\(ans\) 加上 \(Q\) 里的任何元素都会 \(\gt b_i\),贪心的将 \(ans-b_i\) 这段时间花到 \(Q.top\) 上,将 \(Q.top\) 减去 \((ans-b_i)\),将 \(ans\) 改为 \(b_i\),然后把 \(a_i\) 加入 \(Q\),接着考虑 \(i+1\)
  • 在弹出 \(k\) 个数的那一刻,\(ans\) 的值就是选 \(k\) 个人的答案。

Step 4:

对这个贪心做 dp,我们惊奇的发现,只需要记录 \(dp(i,k,popmax,inqmin,ans)\) 表示前 \(i\) 个人,选了 \(k\) 个人,目前在 \(Q\) 里面的钦定被选上的最大值是 \(popmax\),钦定没被选上的最小值是 \(inqmin\),当前的答案是 \(ans\) 的方案数。转移是容易刻画的。

Step 5:

  • \(ans'=\max\{ans,b_{i+1}\}\)
  • 如果 \(ans \le b_{i+1}\),则说明该选的全部选了,\(popmax'=0\),否则 \(popmax'=\min\{popmax,ans-b_{i+1}\}\),这个 \(\min\) 的含义是,如果 \(Q\) 里只有 \(popmax\) 一个元素,则它会变为 \((ans-b_{i+1})\),否则不影响 \(popmax\) 的取值。
  • \(inqmin'=inqmin-ans'+ans\)
  • 枚举 \(a_{i+1}\) 的取值,根据和 \(popmax',inqmin'\) 的关系看能否转移到 \(dp(i+1,k,popmax',\min\{a_{i+1},inqmin'\},ans')\)\(dp(i+1,k+1,\max\{popmax',a_{i+1}\},inqmin',ans'+a_{i+1})\)
  • 处理“弹出 \(k\) 个数的那一刻”,也是简单的,如果 \(popmax\) 存在(为了不数重)且 \(ans \le b_{i+1}\)(确实这一轮能把该选的都选了),就把 dp 状态上的值乘上 \(ans\) 再乘上 \(V^{n-i+1}\) 加到答案里。注意特判 \(i=n+1\)

dp 的五维分别是 \(O(n),O(n),O(V),O(V),O(nV)\) 级别,转移复杂度是 \(O(V)\),故复杂度 \(O(n^3V^4)\),显然状态数不满,且转移常数不大,std 里只优化了取模意义下的加法,能在 \(1s\) 左右跑完。

H. Investors

Step 1:

容易发现题意等价于把整个序列分 \(k\) 段,最小化每一段的逆序对数之和。

Step 2:

直接应用决策单调性:考虑 \(a \lt b \lt c \lt d\),通过讨论逆序对的位置,计算对不等式两边的贡献,可以证明 \(w(a,c)+w(b,d) \le w(a,d)+w(b,c)\)

I. Complexity

Step 1:

最朴素的 dp:\(dp(x_1,y_1,x_2,y_2)\) 表示左上角 \((x_1,y_1)\),右下角 \((x_2,y_2)\) 的子矩形的 complexity。

容易发现答案不超过 \(\log n\),每次劈成相等的两半就行。

Step 2:

考虑另一个 dp:\(dp(c,x_1,y_1,x_2)\),表示对于一个 complexity 不超过 \(c\),左上角为 \((x_1,y_1)\),右下角的 \(x\) 坐标为 \(x_2\) 的子矩形,右下角的 \(y\) 坐标最大是多少。

Step 3:

考虑转移,竖着劈是简单的,直接把 \(dp(c,x_1,dp(c,x_1,y_1,x_2)+1,x_2)\) 的值赋给 \(dp(c+1,x_1,y_1,x_2)\) 即可。

横着劈要枚举劈在什么位置,确定 \(c,x_1,y_1\) 后,这个决策点和 \(x_2\) 是有单调性的,感性理解就是,分界点需要保证两边比较“均衡”。

如果还不理解,那就闭上眼睛想(

复杂度 \(O(n^3 \log^2 n)\)

J. Array Covering

Step 1:

感觉是上凸的,感性理解就是选择的区间权值不断递减,故考虑 wqs 二分,求出将整个序列覆盖的最大代价即可。

Step 2:

令 wqs 二分的附加权值为 \(d\)\(s_i\) 为前缀和。

先把所有贡献为正的区间选上,这些区间 \([l,r]\) 满足 \(s_r-s_{l-1}+d \gt 0\),可以用权值线段树求所有贡献和,并用线段树二分对每个 \(r\) 找到一个最小的 \(l\)

Step 3:

有些位置没有被正区间覆盖,令这些位置为 \(p_1,p_2,\cdots,p_m\),令 \(dp(i)\) 表示覆盖前 \(i\) 个位置的最小代价。

一个观察是不存在两个负区间包含,原因显然,也就是将负区间按左端点从小到大排序,任意相邻两个区间中间没有空隙。

转移 \(dp(j)+\max_{k=p_i}^{p_{i+1}-1} s_k-\min_{l=p_{j-1}}^{p_j-1}s_l +d \rightarrow dp(i)\)

将上下界适当放宽:\(dp(j)+\max_{k=p_i}^{n} s_k-\min_{0}^{p_j-1}s_l +d \rightarrow dp(i)\),容易发现不改变答案。

这个 \(j\) 一定取 \(dp(j)+\min_{l=0}^{p_j-1}s_l\) 最小的 \(j\),预处理前后缀 min 和 max 即可。

K. City United

Step 1:

\(\text{mod} \space 2\) 很奇怪,考虑先在模意义下进行同义替换。令 \(S\) 为点集的一个子集,\(f(S)\)\(S\) 的导出子图的连通块个数。对于 \(f(S)=1\)\(S\) 对答案有 \(1\) 的贡献,其余没有贡献,则答案可以写作 \(\dfrac{\sum 2^{f(S)} \bmod 4}{2}\)

Step 2:

再对于新的式子找组合意义:\(2^{f(S)}\) 表示每个联通块黑白染色的方案数。

Step 3:

对应到原图上就是:用 \(0,1,2\) 三种颜色对顶点染色,其中 \(0\) 表示 \(S\) 中没有这个,\(1,2\) 对应一个联通块的颜色。

要求没有边连接 \(1,2\),可以用状压 dp 解决:\(dp(i,mask)\) 表示染了 \([1,i]\) 中的点,\([i-k+1,i]\) 中的点的染色状态是 \(S\),枚举下一个的颜色转移即可,实现的好可以做到 \(O(n3^k)\),其中 \(k=13\)

L. Desant 3

Step 1:

本题的核心思想是”消去两个相同的状态“。

Step 2:

考虑对 \(m\) 个操作逐层搜索,一个状态记录一个三进制串,\(0/1\) 表示确定当前位是什么,\(2\) 表示还没确定(\(01\) 均可,你可以看做是一种压缩存储)。

Step 3:

依次考虑所有操作:

  • 情况一:\(a_u=a_v=2\),你会发现,若 \(a_u \neq a_v\),则操作之后 \(a_u=0,a_v=1\),因为只需要求模 \(2\) 的结果,两个相同的串可以抵消,故只需要考虑 \(a_u=a_v\) 的两种情况。
  • 情况二:\(a_u,a_v\) 恰好一个为 \(2\)。例如 \(a_u=1,a_v=2\),若 \(a_v=1\),则操作之后 \(a_u=1,a_v=1\);若 \(a_v=0\),则操作之后 \(a_u=0,a_v=1\)。故操作之后可以看成一个 \(a_u=2,a_v=1\) 的状态。另外三种情况同理。
  • 情况三:\(a_u,a_v\) 都不为 \(2\)。直接做一遍这个操作就行。

由于每产生 \(2\) 个分支,\(2\) 的个数减少 \(2\),故复杂度是 \(O(2^{n/2}m)\)

M. Broken Dream

Step 1:

按照 Kruskal 的过程,将边按 \(w_i\) 从小到大排序,令 \(f(i,S),g(i,S)\) 分别表示在加入前 \(i\) 条边的情况下,点集 \(S\) 是一个极大连通块的概率和期望。加入边 \((u,v,w,p)\) 的时候,枚举一个包含 \(u\) 但不包含 \(v\) 的集合 \(S\),和一个包含 \(v\) 但不包含 \(u\) 的集合 \(T\),转移到 \(S|T\)

Step 2:

此时有一个问题,如果之前有一条边,一端在 \(S\) 里一端在 \(T\) 里,我们想让这条边不出现,所以需要乘上这些边的 \((1-p)\) 的积。如果能快速维护出每一对 \(S,T\) 之间的连边,问题就解决了。

Step 3:

考虑维护 \(E(R)\) 表示有一端在集合 \(R\) 里面的边的集合,我们需要支持快速查询 \(E(S)\&E(T)\) 里面所有边的 \((1-p)\) 的积。用四毛子,将边每 \(B\) 个分成一块,每一块预处理 \(2^B\) 种出现的可能带来的贡献,计算的时候把 \(S\) 中连出去的边集,and 上 \(T\) 中连出去的边集,对于每一块 \(O(1)\) 查一下表,算出乘积。

复杂度 \(O(3^nm^2/B+2^BB)\),取 \(B=m/3\) 可以通过。

N. Random IS

Step 1:

\(a_0=0,a_{N+1}=N+1\),假设第一步选择了 \(mid\),能观察到 \([0,mid]\)\([mid,N+1]\) 两段是独立的。

Step 2:

\(dp(l,r)\) 表示区间 \([l,r]\) 的答案,转移 \(dp(l,r)=\frac{\sum_{k=l+1}^{r-1} [a_l \lt a_k \lt a_r](dp(l,k)+dp(k,r)-1)}{\sum_{k=l+1}^{r-1} [a_l \lt a_k \lt a_r]}\)

转移是二维偏序的形式,对每个左端点和右端点开一个 BIT 维护,注意特判合法 \(k\) 数量为 \(0\) 的情况。

复杂度 \(O(n^2 \log n)\)

O. 芒果冰加了空气

Step 1:

考虑将两颗点分树合并:我们会在两个根中选择一个根,并将剩下的那个放进当前根唯一对应子树,递归执行合并过程。

Step 2:

我们要做的实质上是,将两个树根之间的节点归并,剩下的部分都是确定的。

Step 3:

观察到转移系数只和树根在原树中的深度有关,令 \(dp(i,d)\) 表示,考虑 \(i\) 的子树,树根的深度为 \(d\)。转移类似树上背包合并,复杂度 \(O(n^2)\)

P. Zigzag

Step 1:

考虑轮廓线 dp,令 \(dp(i,j,S)\) 表示,考虑到第 \(i\) 条路径的第 \(j\) 个位置,轮廓线的状态是 \(S\)。本题的关键在于如何优秀的刻画轮廓线 \(S\)

Step 2:

不妨用 \(S\) 的前 \(j\) 位记录“新轮廓线”的状态,后 \(n-j\) 位记录“旧轮廓线”的状态。

Step 3:

转移的时候,唯一需要处理的细节是:当旧轮廓线往左,新轮廓线往右时,需要把旧轮廓线的第一个 \(1\) 变成 \(0\)(对应到原图上就是,往右走之后限制变松了,建议在纸上画画或者闭上眼睛想)。

posted @ 2025-04-19 18:13  znstz  阅读(924)  评论(5)    收藏  举报