Atcoder Beginner Contest 275(A~F)

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

希望能越打越好吧……

赛时

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

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

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

则有转移方程:

dpi,j=(k=1km&i+kndpi+k,j1+k=ni+1kmdpnk,j1)×1m

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

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

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

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

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


赛后

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

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

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

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

dpi,j,0=min(dpi1,j,0,dpi1,j,1+1)dpi,j,1=min(dpi1,jai,1,dpi1,jai,0)

初始状态为 dp0,0,1=0。时间复杂度 O(nm)

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

G 没太看懂,不想补了。

posted @   ydtz  阅读(82)  评论(9编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示