2021 小熊的果篮 · 方案二 链表加有序集合
摘掉块头后只影响前后邻居,用 set 维护块头
正文
// CSP-J 2021 复赛 T4 · 小熊的果篮(方案二 · 满分)
// 原题:https://oj.yecheng.tv/p/CSPJ2021D
//
// 方案二 · 双向链表 + 有序集合维护块头
// 每轮重扫太浪费了。真正会变的只有「被挑走的块头的前驱和后继」:
// 把块头 i 摘掉后,它的前驱 p 和后继 q 就挨在一起了 ——
// · 若 p 不存在,或者 a[p] != a[q],那 q 就成了新块的块头;
// · 否则 q 并进了 p 所在的块,不再是一个块头。
// 于是用一个双向链表支持 O(1) 摘除,用一个 set 存当前所有块头。
// 每轮:先把 set 里的块头全部输出,然后统一摘除、再统一更新块头。
// 注意两个坑:
// 1. 必须先把这一轮要摘的全标记成 gone,再判断 q —— 否则会把本轮也要摘掉的点
// 当成下一轮的块头加进 set;
// 2. 摘除和块头更新要分成两趟循环,否则前后驱还没改完,判断就错了。
// 复杂度 O(n log n)。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int a[MAXN], pre[MAXN], nxt[MAXN];
bool gone[MAXN];
int main() {
freopen("fruit.in", "r", stdin);
freopen("fruit.out", "w", stdout);
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
pre[i] = i - 1;
nxt[i] = i + 1;
}
nxt[n] = n + 1;
set<int> heads;
for (int i = 1; i <= n; i++) {
if (i == 1 || a[i] != a[i - 1]) heads.insert(i);
}
while (!heads.empty()) {
vector<int> cur(heads.begin(), heads.end());
heads.clear();
for (size_t k = 0; k < cur.size(); k++) {
cout << cur[k] << (k + 1 == cur.size() ? '\n' : ' ');
}
for (int i : cur) gone[i] = true;
for (int i : cur) { // 第一趟:把 i 从链表里摘掉
int p = pre[i];
int q = nxt[i];
if (p >= 1) nxt[p] = q;
if (q <= n) pre[q] = p;
}
for (int i : cur) { // 第二趟:决定 q 还是不是块头
int p = pre[i];
int q = nxt[i];
if (q > n || gone[q]) continue;
if (p < 1 || a[p] != a[q]) heads.insert(q);
else heads.erase(q);
}
}
return 0;
}
CSP-J 标程 · 复赛真题的其它内容
- 2019 数字游戏 · 方案一 逐字符统计
- 2019 数字游戏 · 方案二 二进制位运算
- 2020 优秀的拆分 · 方案一 贪心从大到小减
- 2020 优秀的拆分 · 方案二 直接看二进制位
- 2021 分糖果 · 方案一 枚举每个 k
- 2021 分糖果 · 方案二 看余数在哪一段
- 2022 乘方 · 方案一 边乘边判断
- 2022 乘方 · 方案二 快速幂加封顶
- 2023 小苹果 · 方案一 照规则真模拟
- 2023 小苹果 · 方案二 只盯住两个数字
- 2024 扑克牌 · 方案一 用集合去重
- 2024 扑克牌 · 方案二 二维布尔表
- 2025 拼数 · 方案一 收集后降序排序
- 2025 拼数 · 方案二 桶计数
- 2019 公交换乘 · 方案一 暴力匹配
- 2019 公交换乘 · 方案二 时间窗口优化
- 2020 直播获奖 · 方案一 每轮排序
- 2020 直播获奖 · 方案二 桶计数
- 2021 插入排序 · 方案一 每次真排一遍
- 2021 插入排序 · 方案二 增量维护有序表
- 2022 解密 · 方案一 二分求整数平方根
- 2022 解密 · 方案二 先估后校开方
- 2023 公路 · 方案一 朴素贪心
- 2023 公路 · 方案二 单调栈预处理
- 2024 地图探险 · 方案一 四方向分支写
- 2024 地图探险 · 方案二 方向数组
- 2025 座位 · 方案一 把座位表填出来
- 2025 座位 · 方案二 直接算排名
- 2019 纪念品 · 方案一 逐天完全背包
- 2019 纪念品 · 方案二 砍掉不赚钱物品
- 2020 表达式 · 方案一 每次重算后缀式
- 2020 表达式 · 方案二 建树加关键性传播
- 2021 网络连接 · 方案一 手写解析
- 2021 网络连接 · 方案二 读入后回拼校验
- 2022 逻辑表达式 · 方案一 递归分治
- 2022 逻辑表达式 · 方案二 递归下降
- 2023 一元二次方程 · 方案一 照公式逐步写
- 2023 一元二次方程 · 方案二 拆成小函数
- 2024 小木棍 · 方案一 先定位数再贪心
- 2024 小木棍 · 方案二 预处理最小数字表
- 2025 异或和 · 方案一 贪心能接就接
- 2025 异或和 · 方案二 动态规划加值域数组
- 2019 加工零件 · 方案一 递归加记忆化
- 2019 加工零件 · 方案二 奇偶最短路
- 2020 方格取数 · 方案一 深搜回溯
- 2020 方格取数 · 方案二 按列动态规划
- 2021 小熊的果篮 · 方案一 每轮扫一遍
- 2022 上升点列 · 方案一 先只考虑不加点
- 2022 上升点列 · 方案二 二维动态规划
- 2023 旅游巴士 · 方案一 分层图加优先队列
- 2023 旅游巴士 · 方案二 状态压成一维
- 2024 接龙 · 方案一 按定义广搜
- 2024 接龙 · 方案二 滑动窗口逐轮推进
- 2025 多边形 · 方案一 枚举所有子集
- 2025 多边形 · 方案二 排序加计数 DP