【CSP-J 2021】 小熊的果篮 解题报告
1 题目链接
2 题目大意
题目名称:小熊的果篮
题目大意:
(这…)
小熊的水果店里摆放着一排
n
n
n 个水果。每个水果只可能是苹果或桔子,从左到右依次用正整数
1
,
2
,
…
,
n
1, 2, \ldots, n
1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里,具体方法是:每次都把每一个“块”中最左边的水果同时挑出,组成一个果篮。重复这一操作,直至水果用完。注意,每次挑完一个果篮后,“块”可能会发生变化。比如两个苹果“块”之间的唯一桔子被挑走后,两个苹果“块”就变成了一个“块”。请帮小熊计算每个果篮里包含的水果。
题目大意:简称题目本身
这除了原文谁说得清啊喂。
3 解法分析
正解似乎有相当多种做法,例如:
O
(
n
n
)
O(n\sqrt{n})
O(nn)、
O
(
n
)
O(n)
O(n)、
O
(
n
log
n
)
O(n\log n)
O(nlogn)等等。
线段树和珂朵莉树过分了啊
显然一眼丁真,链表。然鹅…
《你没
30
m
i
n
30min
30min调不出来系列》
模拟赛就写这东西写挂了(打死我也不会说我最后输出
1
1
1到
n
n
n水到了
10
10
10分)。
这里说一个
O
(
n
log
n
)
O(n\log n)
O(nlogn)的
500
b
y
t
e
500byte
500byte的蒟蒻专属做法罢。
(以上是废话)
首先,要知道set
这个奆容器。
与链表不同,我们可以开两个set
分别用于存放0
与1
的下标。
显然,对于每一行输出,我们只需在两个set
中旋转跳跃即可。
为了方便模拟,我们想到了异或运算,也就是^
。对于一个0
或1
,只需a ^ 1
即可转换。
因此,set
开成set <int> st[2]
会节约许多转换过程。
那么,这道题基本思路已经梳理完了。
细节见代码。
4 AC Code
#include <bits/stdc++.h>
#define N 200007
using namespace std;
int n, a[N];
set <int> st[2];//细节减码量
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]),
st[a[i]].insert(i);//每一个都压入set
}
st[0].insert(1e9);//以判断当前是否已经遍历完
st[1].insert(1e9);//同上
while (*st[0].begin() != 1e9 || *st[1].begin() != 1e9/*0与1都没有遍历完*/) {
for (int i = min(*st[0].begin(), *st[1].begin());//初始化为两边最小,即为开头
i != 1e9; i = *st[a[i] ^ 1].lower_bound(i)) {//不断二分更新
printf("%d ", i);//直接输出
st[a[i]].erase(i);//细节删除
}
puts("");//细节换行
}
return 0;
}//蒟蒻的奇妙码风
5 瞎说
建议各位有机会的话写一写链表。
真锻炼模拟能力。