CSP CCF: 202109-2 非零段划分 (C++)

目录

题目来源

问题描述

题目描述

输入格式

输出格式

样例1输入

样例1输出

样例1解释

样例2输入

样例2输出

样例2解释

样例3输入

样例3输出

样例3解释

样例4输入

样例4输出

样例4解释

子任务

解题思路

代码


题目来源

计算机软件能力认证考试系统

问题描述

试题编号:202109-2
试题名称:非零段划分
时间限制:1.0s
内存限制:512.0MB
问题描述:

题目描述

A1,A2,⋯,An 是一个由 n 个自然数(非负整数)组成的数组。我们称其中 Ai,⋯,Aj 是一个非零段,当且仅当以下条件同时满足:

  • 1≤i≤j≤n;
  • 对于任意的整数 k,若 i≤k≤j,则 Ak>0;
  • i=1 或 Ai−1=0;
  • j=n 或 Aj+1=0。

下面展示了几个简单的例子:

  • A=[3,1,2,0,0,2,0,4,5,0,2] 中的 4 个非零段依次为 [3,1,2]、[2]、[4,5] 和 [2];
  • A=[2,3,1,4,5] 仅有 1 个非零段;
  • A=[0,0,0] 则不含非零段(即非零段个数为 0)。

现在我们可以对数组 A 进行如下操作:任选一个正整数 p,然后将 A 中所有小于 p 的数都变为 0。试选取一个合适的 p,使得数组 A 中的非零段个数达到最大。若输入的 A 所含非零段数已达最大值,可取 p=1,即不对 A 做任何修改。

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 n。

输入的第二行包含 n 个用空格分隔的自然数 A1,A2,⋯,An。

输出格式

输出到标准输出。

仅输出一个整数,表示对数组 A 进行操作后,其非零段个数能达到的最大值。

样例1输入

11
3 1 2 0 0 2 0 4 5 0 2

Data

样例1输出

5

Data

样例1解释

p=2 时,A=[3,0,2,0,0,2,0,4,5,0,2],5 个非零段依次为 [3]、[2]、[2]、[4,5] 和 [2];此时非零段个数达到最大。

样例2输入

14
5 1 20 10 10 10 10 15 10 20 1 5 10 15

Data

样例2输出

4

Data

样例2解释

p=12 时,A=[0,0,20,0,0,0,0,15,0,20,0,0,0,15],4 个非零段依次为 [20]、[15]、[20] 和 [15];此时非零段个数达到最大。

样例3输入

3
1 0 0

Data

样例3输出

1

Data

样例3解释

p=1 时,A=[1,0,0],此时仅有 1 个非零段 [1],非零段个数达到最大。

样例4输入

3
0 0 0

Data

样例4输出

0

Data

样例4解释

无论 p 取何值,A 都不含有非零段,故非零段个数至多为 0。

子任务

70% 的测试数据满足 n≤1000;

全部的测试数据满足 n≤5×105,且数组 A 中的每一个数均不超过 104。

解题思路

       设 非零段 Ai......Aj, 1 <= i <= k<= j<=n, Ak > p。

        1、先定义一个数组A,用于存放Ai,  i 的范围为[0, n + 2]。 A[0] = 0。(左右两端各放置一个0, 方便后续操作)

        2、一层 for 循环。记录 A1......An ,当多个相同的数连在一起时,不记录多余的重复部分(去重)(如 2 3 3 4 5 -> 2 3 4 5)。 同时记录A数组的真实大小 ASize。 A[ASize - 1] = 0;

        3、定义一个 map类型的变量 num2gap:{num, gaps}: 当 p = num时(num 来自 A1....An), 相对于前一个 p 值,增加或者减少的非零段数量 gaps(随意写的单词哈)。

        4、一层 for 循环。 记录每个在A数组中的 Ai 的num2gap。 (具体方法下边讲)

        5、初始化当前的非零段数 curGap = (num2gap.size() == 0? 0: 1)。 如果本组数据全为0, 那么非零段数为0(并且num2gap中无数据)。如果本组数据不全为0, 则默认原始p值为-1,将整体的数据看成一个非零段,因为 Ai > -1, 所以初始为 1 。  此外, 定义一个记录最大非零段数的 ans = curGap。

        6、一层 for 循环。因为 map 是有序的, 所以(有序)遍历 map中的每个元素, 将当前 num对非零段数的影响加进来, 便是 当前 p = num 时, 本次数据的非零段数了。 同时也要记录 最大非零段数哦。

        4 详解:

原始数据:

14
5 1 20 10 10 0 10 15 10 20 1 5 10 15

变成

ASize = 15
A = 0 5 1 20 10 0 10 15 10 20 1 5 10 15 0

   因为本次数据不是全0, 所以 初始非零段数 curGap = 1

  当 p = 0时, curGap = 1 + 1 (A[4] > A[5] < A[6])= 2 。 所以 当 A[i-1] > A[i] < A[i +1] 时, 会增加一个非零段

 当 p = 1时, curGap = 2 + 2(A[1] > A[2] < A[3] / A[9] > A[10] < A[11] ) = 4

  当 p = 5时, curGap = 4 - 1(A[0] < A[1] > A[2]) + 0 (A[10] < A[11] < A[12]) = 3。 所以 当 A[i-1] < A[i] > A[i +1] 时, 会减少一个非零段; 当 A[i-1] < A[i] < A[i +1] 时, 非零段数量不变

  当 p = 10时, curGap = 3 + 0(A[3] > A[4] > A[5]) + 0 (A[5] < A[6] < A[7] / A[11] < A[12] < A[13] ) + 1 (A[7] > A[8] < A[9]) = 4当 A[i-1] >  A[i] > A[i +1] 时, 非零段数量不变

  当 p = 15时, curGap = 4 - 2(A[6] < A[7] > A[8] / A[12] < A[13] > A[14]) = 2。 

  当 p = 20时, curGap = 2 - 2(A[2] < A[3] > A[4] / A[8] < A[9] > A[10]) = 0。 

代码

#include <iostream>
#include <fstream>
#include <map>

using namespace std;

int main() {
    //ifstream cin("in.txt");  // 小技巧!
    int n;
    cin>>n;

    int A[n+2];
    int ASize = 1;
    A[0] = 0;
    for (int i = 1; i <= n; ++i) {
        int tmp;
        cin>>tmp;
        if (A[ASize - 1] != tmp) {
            A[ASize] = tmp;
            ASize++;
        }
    }
    A[ASize] = 0;
    ASize++;

    // 记录各num的gap特征
    map<int, int> num2gap;
    for (int i = 1; i <= ASize - 2; ++i) {
        // 左高右高 gap+1
        if (A[i - 1] > A[i] && A[i] < A[i + 1]) {
            num2gap[A[i]]++;
        }
        // 左低右低 gap-1
        else if (A[i - 1] < A[i] && A[i] > A[i + 1]) {
            num2gap[A[i]]--;
        }
        // 单调递增、单调递减、 gap保持不变
        else {

        }
    }

    // 记录最大gap数
    int curGaps = (ASize == 2? 0: 1);  // 若 Ai 全为0, gap数就为0; 不然初始化gap数为1(相当于p==0);
    int ans = curGaps;
    for (pair<const int, int> &p: num2gap) {
        curGaps += p.second;
        ans = max(curGaps, ans);
    }

    cout<<ans<<endl;

    return 0;
}

------------------------------------- 更新 ----------------------

内存稍微小一些:

将 中间的 A数组 换成了 prepre、 pre、 cur三个整型变量了。

代码:

#include <iostream>
#include <map>

using namespace std;

int main() {
    int n;
    cin>>n;

    // 记录各num的gap特征
    int prepre = 0, pre, cur, i = 0;
    do {
        cin>>pre;
        i++;
    }while (pre == prepre && i < n);

    map<int, int> num2gap;
    for (; i <= n; ++i) {
        if (i < n) {
            cin>>cur;
            if (cur == pre) {
                continue;
            }
        }
        else {
            cur = 0;
        }

        // 左高右高 gap+1
        if (prepre > pre && pre < cur) {
            num2gap[pre]++;
        }
        // 左低右低 gap-1
        else if (prepre < pre && pre >cur) {
            num2gap[pre]--;
        }
        /*
        // 单调不下降/ 单调不上升, gap 保持不变
        else if ( (prepre < pre && pre < cur) || (prepre > pre && pre > cur)) {

        }
        */
        prepre = pre;
        pre = cur;
    }

    // 记录最大gap数
    int curGaps = (num2gap.size() == 0? 0: 1);  // 若 Ai 全为0, gap数就为0; 不然初始化gap数为1(相当于p==-1);
    int ans = curGaps;
    for (pair<const int, int> &p: num2gap) {
        curGaps += p.second;
        ans = max(curGaps, ans);
    }

    cout<<ans<<endl;

    return 0;
}

<think>好的,我现在需要回答用户关于CCF-CSP比赛规则或赛制的问题。用户已经提供了四个引用来源,我需要仔细分析这些信息,并整理出一个结构清晰的回答。 首先,我要确认用户的问题核心是CCF-CSP的赛制规则,可能包括认证级别、考试内容、评分规则、认证时间和形式等方面。接下来,我需要从提供的引用中找到相关信息。 引用[1]提到CCF CSP认证是计算机软件能力认证,属于职业资格认证。引用[2]指出CSP-J/S分两个级别,不设年龄限制,面向非专业级。引用[3]补充了CSP-JS分为入门组和提高组,涉及算法和编程,并且提到了GESP一级认证的情况。引用[4]则强调了需要扎实的基础知识和实践经验,无论是个人还是团队参赛。 接下来,我需要将这些信息整合成几个关键点。比如,认证级别分为CSP-J和CSP-S,考试内容可能包括算法和编程题,评分规则可能涉及题目得分和等级评定,认证时间可能每年举办,形式为机试。 需要注意的是,用户提供的引用中没有详细的评分细则,比如每题分值或通过标准,所以可能需要说明具体评分规则需参考当年公告。同时,引用[2]提到了第二轮认证,可能说明赛制分为初赛和复赛,但需要确认是否适用于所有级别的认证。 另外,引用[3]提到了GESP Python认证一级,这可能与CSP不同,但用户问题集中在CSP上,所以可以暂时忽略这部分,除非有直接关联。 整理时还要确保回答结构清晰,分点列出,并自然地添加引用标识。最后,生成的相关问题需要与CCF-CSP的赛制相关,比如认证难度、备考方法、与其他竞赛的区别等。 现在需要检查是否有遗漏的信息或可能的错误。例如,引用[2]提到CSP-J/S2020第二轮认证,可能意味着CSP-J/S分为两轮,但引用[4]没有明确说明,因此需要谨慎表述,指出通常分为两轮,但具体以官方公告为准。 总结下来,回答应包含以下几个部分:认证级别、考试内容、评分规则、认证时间和形式,以及注意事项。每个部分引用对应的来源,并在末尾生成相关问题。</think>### CCF CSP比赛规则与赛制详解 #### 1. **认证级别与分组** CCF CSP认证分为**非专业级别(CSP-J/S)**和**专业级别**。其中: - **CSP-J(入门组)**:面向算法和编程基础较弱的初学者。 - **CSP-S(提高组)**:面向有一定编程和算法能力的学习者[^3]。 - 专业级别认证(如GESP)则针对更高级别的编程能力评估,例如Python一级认证等[^3]。 #### 2. **考试内容** - **题型**:以算法和编程题为主,涵盖数据结构、动态规划、图论等计算机科学核心内容。 - **形式**:上机编程,需在限定时间内完成题目并提交代码[^4]。 - **难度分级**:CSP-J题目相对基础,CSP-S题目复杂度更高,涉及更深入的算法设计。 #### 3. **评分规则** - **得分机制**:每题按测试用例通过比例得分,例如某题有10个测试点,通过6个则得60%分数[^2]。 - **等级评定**:根据总分划分等级(如A/B/C),具体分数线由CCF官方在考试后公布[^2][^4]。 #### 4. **认证时间与形式** - **频率**:每年举办多轮认证,例如CSP-J/S通常分为初赛和复赛两轮。 - **初赛**:多为笔试或在线理论考试,筛选进入复赛的选手。 - **复赛**:上机编程实践,决定最终成绩[^4]。 #### 5. **参赛资格与注意事项** - **资格**:无年龄、职业限制,学生和在职人员均可报名。 - **团队参赛**:部分赛事允许团队协作,但需遵守具体规则[^4]。 - **认证用途**:CSP成绩可作为高校录取、企业招聘的参考依据[^1]。 #### 注意事项 - 具体赛制可能因年份调整,需以**CCF官方公告**为准。 - 编程语言通常支持C++、Java、Python等,需提前确认环境要求。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值