AtCoder Educational DP Contest 题解

Educational DP Contest - AtCoder

点开链接即可看到题目

可以在洛谷看AT4522~AT4547

A~C

真正的入门题。

D~E

01背包模板。

F

最长公共子序列。

G

「DAG上的DP」入门。

H

二维DP入门。

I - Coins

简单概率DP,设f[i][j]表示前i枚硬币中有jj枚朝上的概率。比较容易推出转移方程

J - Sushi

一看题,发现不那么好设计状态。发现操作与盘子顺序无关,所以决定一个状态本质的只有「有1个寿司」「有2个寿司」「有3个寿司」的盘子的数量。

设f[i][j][k]表示还有i个盘子剩1个寿司、j个盘子剩2个寿司、k个盘子剩3个寿司的剩余操作次数的期望。

考虑从操作完的状态(f[0][0][0])往回推。在状态aa从状态b转移来时,aa的期望操作次数即为从(0,0,0)到bb的期望操作次数加上从bb到aa的期望操作次数(还要乘上转移概率)。设当前状态为f[i][j][k],记sum=i+j+k>0

首先,第一行是取到非空盘子的期望次数。显然选中非空盘子的概率为\frac{sum}{n}nsum​,记为p,那么从开始操作到第一次选中非空盘子,期望操作次数为

i=1∑+∞​i(1−p)i−1p=pi=1∑+∞​i(1−p)i−1=p1−p∑i=1+∞​i(1−p)i​=p1−p[1−(1−p)]21−p​​=p1​

然后,第二行中\frac{a}{sum}suma​是在选中有寿司的盘子的条件下,选中「有1个寿司的盘子」的概率(条件概率)。所以(在选中有寿司的盘子的条件下)有\frac{a}{sum}suma​的概率到达状态(i-1,j,k),则本状态的期望操作次数加上「目标状态的期望操作次数 × 到达目标状态的概率」。

第三、第四行同理。初始状态f[0][0][0]=0

K - Stones

这题属于「博弈论入门-公平组合游戏」。

定理 1:没有后继状态的状态是必败状态。

定理 2:一个状态是必胜状态当且仅当存在至少一个必败状态为它的后继状态。

定理 3:一个状态是必败状态当且仅当它的所有后继状态均为必胜状态。

状态很清楚了,就是当前剩余的石子数。设f[k]=0/1表示该状态是必胜/必败状态。从小到大转移(博弈过程的相反方向),枚举它的后继状态(在DP中是前驱状态),用定理判定即可。由于枚举的状态总是比当前状态小,所以无后效性。

 L - Deque

题中的操作是取头/尾,又是DP,那么一般是区间DP。

一般地,设f[i][j]表示区间[i,j]形成的Deque博弈结束时的x-y的值。

如何转移?设len=i-j+1,则:f[i][j]=\begin{cases} \min(f[i][j-1]-a_j,f[i+1][j]-a_i) & n-len\equiv 1\pmod 2 \\ \max(f[i][j-1]+a_j,f[i+1][j]+a_i) & n-len\equiv 0\pmod 2 \end{cases}f[i][j]={min(f[i][j−1]−aj​,f[i+1][j]−ai​)max(f[i][j−1]+aj​,f[i+1][j]+ai​)​n−len≡1(mod2)n−len≡0(mod2)​

显然,初值f[i][i]=\begin{cases} -a_i & n\equiv 0\pmod 2 \\ a_i }

如何理解?以n-len\equiv 1\pmod 0n−len≡1(mod0)的情况为例。在这个情况下,已经取过的数的个数为偶数,那么在[i,j][i,j]时轮到先手(Taro)。那么,他会从删去左边元素、删去右边元素的博弈结果中选出最大值,因为他的目标是最大化x-yx−y。这和状态转移方程是一致的。n-len\equiv 1\pmod 1n−len≡1(mod1)的情况也一样,只不过取\min,而且a_i对x-y的贡献是-a_i,因为是y增加了a_i。

这题将动态规划思想与博弈论紧密结合在了一起,以博弈者的视角从后继状态(DP的前驱状态)中选出最优的一个。

M - Candies

状态中记录分发到前i个人,恰好总共分发了j个糖果的方案数。前缀和优化转移即可。

N - Slimes

石子合并。

O - Matching

显然状压DP。记f[i][S]f[i][S]表示配对完前ii个男士,配对的女士集合为S的方案数,而popcount(S)=ipopcount(S)=i,第一维可以不要。外层循环枚举男士i,内层循环枚举女士jj,然后枚举大小为i-1i−1的集合尝试转移。

通过的关键是枚举大小为kk的子集的时间是C_{n}^{k}而不是2^n。那么总的时间为\sum_{i=1}^{n}{\sum_{j=0}^{n-1}{C_n^{i-1}}}=n\sum_{i=0}^{n-1}{C_n^i}=n\times(2^n-1)i=1∑n​j=0∑n−1​Cni−1​=ni=0∑n−1​Cni​=n×(2n−1)

P - Independent Set

树上DP入门。

Q - Flowers

数据结构优化DP。或者叫「最大权值和上升子序列」。

R - Walk

「矩阵快速幂实现DP转移」入门。我觉得USACO 2007 November Gold - Cow Relays更有意思。

S - Digit Sum

数位DP入门。状态只需记录当前从高到低第x位,数位的和模d的值,是否确定小于k。

T - Permutation

如果DP的是一个排列,那么在状态设计上有一些技巧。

状态比较难设计。设f[i][j]表示完成了p的前i个数,未填的数中还有j个大于p_i的数的方案数。第二维巧妙地记录了状态之间数的大小关系变化(具体看转移)。

转移比较好推。所以f[i][j]=\begin{cases} \sum_{k=j+1}^{n-1}{f[i-1][k]} & s_{i-1}='<'\\ \sum_{k=0}^{j}{f[i-1][k]} & s_{i-1}='>' \end{cases}

意思是:若当前填的数小于前一个数,那么当前位置的j大于等于前一个;若当前填的数大于前一个数,那么当前位置的j小于前一个。

U - Grouping

经典题。枚举子集的子集,时间复杂度是O(3^n)

设f[S]表示将集合S中的兔子划分了,能得到的最高分数。不知道转移路径,所以记忆化搜索。搜索时先计算不划分当前集合SS的分数,然后枚举集合T,要求T\subsetneqq S,递归计算将S划分成T和S-T的最大分数,取\max即可。

无后效性是显然的,因为一个集合只会从它的真子集转移过来。

V - Subtree

换根DP经典题。

先考虑普通DP,设f[i]f[i]表示ii必须染成黑色时以ii为根的子树染色方案。则f[u]=\prod_{v\in son(u)}{(f[v]+1)},加一代表该子树染成白色。

这题毒瘤在于给定的模数不一定是质数,那么换根走向子节点时无法很好地去除该节点对父节点的贡献。处理方法是记录每个节点儿子的(f+1)的前缀积、后缀积,换根时直接利用它O(1)重算父节点的值即可。注意,换根时父节点将变为当前根的子节点,此时当前根多了一个儿子,却无法更新当前根的前缀积、后缀积;由于每个点增加的子节点最多一个,开个数组记录就好了。

W - Intervals

数据结构优化DP 进阶。

官方题解认为这是最难的一题,我认为也是。

设f[i][j]为当前到第ii个数,在i前面离它最近的一个1在j位置,并且只计算右端点小于等于i的区间,得到的最大分数。

则f[i][j]=\begin{cases} f[i-1][j]+\sum_{l_k\leq j,r_k=i}{a_k} & j

仔细观察,从给定区间的角度考虑,发现f[j]+=\sum_{l_k\leq j,r_k=i}{a_k}f[j]+=∑lk​≤j,rk​=i​ak​实际上是给[l_k,r_k)的每个j对应的f[j]加上a_k,这是熟悉的区间加操作。而f[j]=\max_{0\leq p

整理一下,状态转移分两步:

  1. f[i]\leftarrow \max_{0\leq p
  2. 对每个右端点为ii的区间kk,在ff数组[l_k,i]区间加上a_k。

显然这个转移和最初的转移是等价的,所以正确性由最初的转移方程保证。用数据结构维护即可。

 X - Tower

贪心+DP。这种题一般是先推出某个贪心结论,剩下的决策用DP做,降低复杂度。

对一个从底部到顶部的序列1-2-3-4(编号)

观察交换1,2前后,剩余承重能力的变化:

前:min(s_1-w_2-w_3-w_4,s_2-w_3-w_4)

后:min(s_2-w_1-w_3-w_4,s_1-w_3-w_4)

观察到:\Delta s_{remain}=min(s_2-w_1,s_1)-min(s_1-w_2,s_2)

还要讨论两个方块是否能放在对方的下面:当s_1-w_2<0,s1​−w2​<0,时,两个不会同时选中,无需考虑相对顺序;当s_1-w_2<0,s_2-w_1>0时,上式大于0;当s_1-w_2>0,s_2-w_1<0时,上式小于0。

所以,上式若大于0,则2放下面合法且更优,因为这样提供了更多的剩余承重能力。于是找到了一个顺序。排序即可。剩余的类似背包,设f[i][j]表示当前决策从下到上第i个,剩余承重能力为j时的最大价值,转移很容易。

Y - Grid 2

用数学方法进行计数的DP。目测原题详见Codeforces 559C。

考虑基于墙(不能经过的点)计数。为了方便,设(H,W)也是一堵墙,并且令n\leftarrow n+1。

方法 1

利用巧妙的状态设计,可以不用容斥原理。

具体地说,设f[i]表示从1到i点,路径上不经过i以外的墙的路径总数。

则f[i]=(从(1,1)到i点的路径总数)——(从(1,1)到i点至少经过一个墙的路径总数)

前半部分很明显,是C_{x_i-1+y_i-1}^{x_i-1};

后半部分为\sum_{0< j < i,x_j\leq x_i,y_j\leq y_i}{(f[j]\times C_{x_i-x_j+y_i-y_j}^{x_i-x_j})}

即枚举j作为「第一个」经过的墙,后面随便走。

这样任意两个jj所对应的路径都是不重复的,因为「经过的第一个墙」不同。同时也不会漏统计。时间复杂度O(n^2)。

方法 2

另一种状态设计:用容斥原理,设f[i][j]是走到第i个墙,并经过了j个墙的方案数

则ans=f[i][1]-f[i][2]+f[i][3]-f[i][4]......将奇数、偶数j分别拼在一起转移,可以优化至O(n^2)

 Z - Frog 3

题目名字真的是首尾呼应。

设f[i]表示跳到i的最小花费

朴素转移方程:f[i]=\min_{1\leq j

朴素转移时间复杂度O(n^2)

处理转移方程:f[i]=\min{(f[j]+h_i^2-2h_ih_j+h_j^2+C)} =\min{(-2h_jh_i+f[j]+h_j^2)}+h_i^2+C

把h_i​看做自变量,\min里面那一堆显然是一条直线方程.

如果h没有单调性,用「李超线段树」,把这些直线插入,转移时查询,这题O(n\log n)就做完了。

可是我不会「李超线段树」!那么就用「斜率优化」。

拆掉\min,有f[i]=-2h_ih_j+f_j+h_j^2+h_i^2+C

设决策点j_1,j_2(j_2>j_1),若j_2优于j_1​,则有-2h_ih_{j_2}+f_{j_2}+h_{j_2}^2+h_i^2+C−2hi​hj2​​+fj2​​+hj2​2​+hi2​+C≤−2hi​hj1​​+fj1​​+hj1​2​+hi2​+C

化简得\frac{(f_{j_2}+h_{j_2}^2)-(f_{j_1}+h_{j_1}^2)}{h_{j_2}-h_{j_1}}

对每个jj描点(h_j,f_j+h_j^2),画出图来马上就能理解,然后易证若j_1,j_2,j_3中j_2​是上凸点,那么它不会成为最优,所以维护下凸壳。

由上面式子可知,最优决策点是下凸壳中第一条斜率大于2h_i​的线段的左端点。画图也容易理解。

且由于2h_i​单调递增,所以具有决策单调性,在最优决策点左边的点可以直接扔掉了。然后用队列O(n)O(n)解决。

类似P1419 寻找段落。

你可能感兴趣的:(c++)