Atcoder Beginner Contest 275(A~F)

我好菜啊……又没切掉 F,40+ min 切掉 A~E 成功滚粗。

希望能越打越好吧……

赛时

A 求序列最大值,B 简单计算,C 数正方形,跳过。

D 递推不太行,N 的范围有点大。但是除法的转移十分稀疏,所以可以考虑记忆化搜索,用一个 map 存储即可。

E 简单概率 dp,考虑从终止状态开始进行转移。不妨设 \(dp_{i,j}\) 表示当前走到 \(i\),且转了 \(j\) 次转盘的获胜概率。

则有转移方程:

\[dp_{i,j}=(\sum_{k=1}^{k\le m\&i+k\le n} dp_{i+k,j-1}+\sum_{k=n-i+1}^{k\le m}dp_{n-k,j-1})\times\frac{1}{m} \]

由于到达终点之后无论转几次都是必然获胜,所以将这些初始状态都设为 \(1\) 即可。

F 想到我们不可能将两段相邻的段算作删两次,所以我们选的段和删的段显然是两两交错的。且由于我们要算出 \(x=[0,m]\) 的每一个答案,所以我们可以考虑按照段进行 dp。

那么假设我们知道了 \(dp_{0}\)\(dp_{i-1}\) 选几段,我们应该是可以通过某一个值的序列状态再选一段删除得到 \(dp_i\) 的,而为了保证无后效性,我们再加一维序列维,设 \(dp_{i,j}\) 表示当前总和为 \(i\),且删到第 \(j\) 个位置时最少删几段,转移即可。

但是此时我们转移的时候即需要枚举当前这一段选多长(从 \(i\) 向前删到的位置 \(j\)),还需要找到 \(j\) 前面的合法决策,即使我们使用数据结构维护,时间复杂度也会达到 \(O(n^2m\log n)\)

然后就陷入了局限性思维,出不来了,草草结束了这场比赛。


赛后

F 其实我们可以发现,我们的状态设计已经很精简了,我们只能从转移下手优化时间复杂度。

有一个很经典的套路是,如果按段转移不好转移,我们就可以考虑从前一个位置怎么转移。如果可以直接从前一个位置转移,我们一般就可以将转移的时间复杂度优化到 \(O(1)\) 了。

我们将序列中的每一个位置选择或者不选择用一个 \(0/1\) 序列来表示。那么真正算入答案贡献的 \(0\) 只有位于第一个位置的 \(0\) 以及前面位置是 \(1\)\(0\)。那么如果从上一个位置进行转移,我们其实只会关注上一个位置选了还是没选,如果上一个位置选择,当前位置不选,段数就会多 \(1\);其他情况段数都不会增加。

总结来说,我们设 \(dp_{i,j,0/1}\) 表示对于序列的前 \(i\) 个位置,当选择的总和为 \(j\),且第 \(i\) 个位置选或者不选时的最小删除段数,则有:

\[dp_{i,j,0}=\min(dp_{i-1,j,0},dp_{i-1,j,1}+1)\\ dp_{i,j,1}=\min(dp_{i-1,j-a_{i},1},dp_{i-1,j-a_i,0}) \]

初始状态为 \(dp_{0,0,1}=0\)。时间复杂度 \(O(nm)\)

(ps:破案了,前缀和优化 = 从上一个转移,人有点傻,勿怪)

G 没太看懂,不想补了。

posted @ 2022-10-30 11:41  ydtz  阅读(81)  评论(9编辑  收藏  举报