Loading

P7078 [CSP-S 2020] 贪吃蛇 解题报告

一道有意思的 ad-hoc,难点在于模拟。

这个限制非常强:如果不吃的话游戏直接结束,就吃不到了。那么肯定是吃了不会寄就吃。

那么显然,如果吃完之后不是最小值,那肯定不会寄,一定吃。

如果吃完之后是最小值,那么就看一下她吃完之后下一个最大的蛇会不会选择吃。

那么解法其实很显然了:假如现在剩下 \(i\) 条蛇,那么每一条蛇的长度其实是唯一确定的。因此,我们可以计算 \(i = [1, n]\) 时所有蛇的状态。

然后同时进行一个 DP。设计 \(f_i\) 代表剩下 \(i\) 条蛇时,最大的是否会选择把最小的吃掉。

  • case 1:吃完之后不是最小值,有 \(f_i = 1\)

  • case 2:吃完之后是最小值,有 \(f_i = [f_{i - 1} = 0]\)

因为这个 DP 是线性的,所以瓶颈可能会出现在计算蛇的长度上。

考虑如果使用 std::set 进行预处理的话,贡献的时间复杂度是 \(\mathcal{O}(n \log n)\) 的。这在 \(T \le 10, n \le 10^6\) 的数据下非常危险。

不过按照现在的评测机来看,或许卡卡能过。

其实有一种优化到线性的做法:

考虑 case 2。如果当前 case 2 吃掉之后,下一条蛇碰到的是 case 1,那么一定会寄,所以不会吃。

所以我们可以把整过过程分为两个阶段:首先是一直 case 1,然后一直 case 2。

有一个套路就是:我们使用两个 std::deque \(p,q\) 来模拟这个容器,一开始所有数都在 \(p\) 里。

考虑在 case 1 里,每条蛇吃完之后不是最小值,所以 \(q\) 只需要维护最大值,这个很容易。

第一次吃完之后变成最小值时,我们进入 case 2 阶段。此时,我们发现,对于吃完剩下的这个最小值,已经不需要再放入容器中了,单独算一下就好了。

posted @ 2026-08-29 11:59  Trent900  阅读(18)  评论(0)    收藏  举报