P7912 [CSP-J 2021] 小熊的果篮 题解

题面

题目解析

题目还是很好理解的,就是给你一个非零即一的序列,让你每一轮在每一个里拿出最前面的水果,然后输出

有很多人用都是链表的做法,但是对于我这种不会链表的怎么办呢?

很容易发现,无论有没有合并,01都是交替拿的,而且拿到的一定比现在的下标大

可以把所有的0放在一个有序数组里,所有1放在一个有序数组里,然后从小到大交替拿就可以

可以用set维护有序数组,而查找就用二分,时间复杂度\(O(nlogn)\)

代码如下

#include <bits/stdc++.h>

using namespace std;

constexpr int inf = 2e5 + 2;
set<int> x, y;

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int n;
    cin >> n;

    x.insert(inf), y.insert(inf); // 防止空set错误
    int c;
    for (int i = 1; i <= n; i++) {
        cin >> c;
        if (!c)
            x.insert(i);
        else
            y.insert(i);
    }

    int p = 1, now = 0;
    if (*x.begin() < *y.begin()) p = 0; // 一开始要从小开始拿

    while ((!p && x.size() > 1) || (p && y.size() > 1)) {
        if (!p) {
            now = *x.upper_bound(now); // 二分
            if (now == inf) {
                cout << '\n';
                now = 0;
                if (*x.begin() < *y.begin())
                    p = 0;
                else
                    p = 1;
                continue;
            } else {
                cout << now << " ";
                x.erase(now);
                p = !p;
            }
        } else {
            now = *y.upper_bound(now);
            if (now == inf) {
                cout << '\n';
                now = 0;
                if (*x.begin() < *y.begin())
                    p = 0;
                else
                    p = 1;
                continue;
            } else {
                cout << now << " ";
                y.erase(now);
                p = !p;
            }
        }
    }
    cout << '\n';
    for (int i : x) // 输出剩余的数
        if (i != inf) cout << i << '\n';
    for (int i : y)
        if (i != inf) cout << i << '\n';
    return 0;
}

听懂?点赞?

posted @ 2026-04-05 07:57  PCMSFV  阅读(2)  评论(0)    收藏  举报