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

是模拟吗?

其实是的,虽然 $1 \le n \le 2 \times 10^5$,但是队列是个好东西.

我们定义一个结构体,来存放每一个块的信息,包括类型、起点、终点,将它们放入

队列当中,再使用基于广搜的思想,先处理,再合并,所以需要用到 $2$ 个队列.

注意点

数据中可能会有块的类型全是 $1$,或者全是 $0$ 的情况,所以保险起见,特判一下.

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>

using namespace std;

int n, a[200005], p;

struct node{
    int start, end, type; // 类型,起点,终点
};

// vis[i] 表示当前水果是否被取走
bool vis[200005];

queue<node> q, q1;

bool all_1() {
    for (int i = 1; i <= n; i++) {
        if (a[i] == 0) return 0;
    }
    return 1;
}

bool all_0() {
    for (int i = 1; i <= n; i++) {
        if (a[i] == 1) return 0;
    }
    return 1;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    if (all_1() || all_0()) { // 特判全是 1 或者 0 的情况
        for (int i = 1; i <= n; i++)
            printf("%d\n", i);
        return 0;
    }
    a[n+1] = 21474836; // 设下截止点
    int s = 1;
    for (int i = 2; i <= n + 1; i++) {
        if (a[i] != a[i-1]) { // 发现新的类型
            q.push((node){s, i - 1, a[i-1]}); // 存入
            s = i; // 更新起点
        }
    }
    int cnt = n; // 水果数量
    while (cnt) {
        while (!q.empty()) {
            node f = q.front();
            q.pop();
            // 找到当前能拿水果的起点
            while (vis[f.start] && f.start <= f.end) f.start++;
            // 出界了
            if (f.start > f.end) continue;
            printf("%d ", f.start);
            cnt--; // 水果数量减少
            vis[f.start] = 1; // 当前水果被拿走了
            if (f.start == f.end) continue; // 没有能拿的
            f.start++;
            q1.push(f); // 放入合并队列
        }
        printf("\n");
        node u;
        while (!q1.empty()) {
            u = q1.front();
            q1.pop();
            while (!q1.empty()) {
                node x = q1.front();
                if (u.type == x.type) { // 相同种类
                    u.end = x.end; // 合并
                    q1.pop();
                }
                else break; // 否则退出(只能合并相邻的2个)
            }
            q.push(u); // 存入新的块
        }
    }
    return 0;
}

根据提供的引用内容,CSP-J2021复赛有两道题目,分别是分糖果和小熊果篮。 对于第一题分糖果,题目来源是CCF,难度为入门。根据给出的代码,这是一个基于循环的算法,通过遍历[l,r]区间内的数,计算数对n取模后的最大值。具体的实现细节可以参考引用中的代码。这道题目属于入门级别,比较简单。 第二题是关于小熊果篮。给定一个长度为n的数组a,其中连续的相同元素被视为一个块,要求按照块的顺序输出每个块的头元素,并删除已输出的元素。具体的实现细节可以参考引用中的代码。这道题目需要使用双链表来处理,时间复杂度为O(n)。 综上所述,CSP-J2021复赛的题目包括分糖果和小熊果篮,具体的解题思路和代码实现可以参考上述引用内容。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [[CSP-J 2021]比赛题解](https://blog.youkuaiyun.com/weixin_56550385/article/details/126811201)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [新鲜出炉的 CSP-J 2021 复赛题目 题解](https://blog.youkuaiyun.com/qq_23109971/article/details/121024436)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值