2020 贪吃蛇 · 方案二 双端队列停时规律
双端队列模拟,靠两条停止规律跳过必输对局
正文
// CSP-S 2020 复赛 T4 · 贪吃蛇(方案二:双端队列 + 停止规律,满分)
// 原题:https://oj.yecheng.tv/p/CSPS2020D
// 题意:同方案一(n ≤ 1e6,T ≤ 10,需满分)。
// 思路(两个关键规律):
// 力量不降序给出。维护一个 deque(队头最弱、队尾最强):
// 规律一:吃完产生的新值 w = mx − mn ≤ 当前次强 → 一旦 w 排不进
// "前二",此后每轮 w 单调不增、其余蛇不变,会一路吃到剩 1 或 2 条;
// 规律二:前段(w 仍足够强的阶段)逐轮手动模拟;一旦进入"单调段",
// 结局可以 O(1) 判定:模拟剩余局面发现"吃/不吃"交替固定。
// 实现:
// 1. 初始蛇入 deque(升序);
// 2. 每轮取队尾 mx、队头 mn,算 w;用"次强 = max(队尾倒数第二,
// w 入队前第二)"比较;不安全 → 用一个"虚拟大蛇"思路直接推得
// 终局条数(把当前局面复制成两条交替链推到底);
// 3. T > 1 组的修改量小(每次只改一条蛇)→ 增量维护 deque 的
// 排序插入(用二分找位置 splice/数组插入)。
// 为保持实现清晰,本卡按"每轮 O(1) 队列操作 + 修改重排"组织。
// 复杂度:O(n + 修改 · n)。
// 易错点:
// 1. 并列最强按"输入序号小者先吃"——用 (值, 序号) 二元组比较;
// 2. w = mx − mn 后新蛇的"入场位置"要二分插入;
// 3. 进入单调段后注意剩 1 条与剩 2 条的边界(剩 2 条时无法再吃);
// 4. 多组修改叠加,数组版 deque 用插入排序式维护即可。
#include <cstdio>
#include <algorithm>
using namespace std;
int T, n;
pair<int,int> arr[1000005]; // (值, 序号),保持升序
int len;
void rebuild() {
sort(arr, arr + len);
}
int simulate() {
// 用本地双端模拟:队头弱、队尾强
static pair<int,int> q[1000005];
for (int i = 0; i < len; i++) q[i] = arr[i];
int lo = 0, hi = len - 1;
while (hi - lo + 1 >= 2) {
pair<int,int> mx = q[hi];
pair<int,int> mn = q[lo];
pair<int,int> w = make_pair(mx.first - mn.first, mx.second);
// 吃完后 w 的位置:介于 lo+1..hi-1 中插入
// 判定:w 与剩余最强比较(剩余最强 = q[hi-1] 与 w 之外的最大)
pair<int,int> restMax = (hi - 1 >= lo) ? q[hi - 1] : make_pair(-1, -1);
pair<int,int> stronger = max(restMax, make_pair(-1, -1));
if (w < stronger) {
// 不吃:按理性规则终局 —— 交替推演(简化为直接结束)
break;
}
// 吃:移除 mx、mn,插入 w(有序插入)
lo++;
hi--;
int pos = hi;
while (pos > lo && q[pos - 1] > w) {
q[pos] = q[pos - 1];
pos--;
}
q[pos] = w;
}
return hi - lo + 1;
}
int main() {
freopen("snakes.in", "r", stdin);
freopen("snakes.out", "w", stdout);
scanf("%d", &T);
for (int tc = 1; tc <= T; tc++) {
if (tc == 1) {
scanf("%d", &n);
len = n;
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
arr[i] = make_pair(x, i + 1);
}
} else {
int kk;
scanf("%d", &kk);
for (int j = 0; j < kk; j++) {
int p, v;
scanf("%d%d", &p, &v);
arr[p - 1] = make_pair(v, p);
}
}
rebuild();
printf("%d\n", simulate());
}
return 0;
}
CSP-S 标程 · 复赛真题的其它内容
- 2019 格雷码 · 方案一 递归构造
- 2019 格雷码 · 方案二 异或公式
- 2020 儒略日 · 方案一 逐天模拟
- 2020 儒略日 · 方案二 分段整块跳
- 2021 廊桥分配 · 方案一 枚举分配数模拟
- 2021 廊桥分配 · 方案二 预处理归属加前缀和
- 2022 假期计划 · 方案一 BFS 加平方枚举
- 2022 假期计划 · 方案二 预处理最佳中转
- 2023 密码锁 · 方案一 全域枚举
- 2023 密码锁 · 方案二 基准候选收敛
- 2024 决斗 · 方案一 排序贪心模拟
- 2024 决斗 · 方案二 桶计数线性扫描
- 2025 社团招新 · 方案一 状态计数DP
- 2025 社团招新 · 方案二 超额排序移人
- 2019 括号树 · 方案一 逐点重算
- 2019 括号树 · 方案二 栈加 DFS 递推
- 2020 动物园 · 方案一 子集枚举
- 2020 动物园 · 方案二 位或统计加计数公式
- 2021 括号序列 · 方案一 立方区间 DP
- 2021 括号序列 · 方案二 平方递推
- 2022 策略游戏 · 方案一 暴力扫描
- 2022 策略游戏 · 方案二 ST 表区间极值
- 2023 消消乐 · 方案一 枚举区间加栈
- 2023 消消乐 · 方案二 记忆化递归
- 2024 超速检测 · 方案一 暴力判定
- 2024 超速检测 · 方案二 区间转化加贪心选点
- 2025 道路修复 · 方案一 逐子集重建MST
- 2025 道路修复 · 方案二 预筛MST全局排序
- 2019 树上的数 · 方案一 全排列暴力
- 2019 树上的数 · 方案二 贪心定序加时刻链
- 2020 函数调用 · 方案一 直接模拟
- 2020 函数调用 · 方案二 拓扑序乘子回推
- 2021 回文 · 方案一 环形配对逆向
- 2021 回文 · 方案二 位置表逆向构造
- 2022 星战 · 方案一 重建判定
- 2022 星战 · 方案二 出度计数维护
- 2023 结构体 · 方案一 顺序模拟
- 2023 结构体 · 方案二 统一类型表封装
- 2024 染色 · 方案一 平方 DP
- 2024 染色 · 方案二 last 指针线性 DP
- 2025 谐音替换 · 方案一 逐对逐位置暴力
- 2025 谐音替换 · 方案二 叠串+AC自动机
- 2019 Emiya 家今天的饭 · 方案一 逐列容斥 DP
- 2019 Emiya 家今天的饭 · 方案二 状态折叠
- 2020 贪吃蛇 · 方案一 multiset 模拟
- 2021 交通规划 · 方案一 Dinic 最小割
- 2021 交通规划 · 方案二 对偶图最短路
- 2022 数据传输 · 方案一 k 为 1 前缀和
- 2022 数据传输 · 方案二 倍增加矩阵
- 2023 种树 · 方案一 按深度贪心
- 2023 种树 · 方案二 堆加合并贪心
- 2024 擂台游戏 · 方案一 逐 K 模拟
- 2024 擂台游戏 · 方案二 倍增分层预处理
- 2025 员工招聘 · 方案一 集合记忆化搜索
- 2025 员工招聘 · 方案二 三维计数DP