[蓝桥杯]欢迎参加福建省大学生程序设计竞赛【算法赛】

问题描述

20232023 年 1313 月 32∼3332∼33 日,福建省第十一届大学生程序设计竞赛在东南大学如期举办。来自厦门大学、福州大学、集美大学、华侨大学、福建师范大学等 100100 所高校的 nn 支队伍参赛。

  • 华侨大学“红日初升”代表队,以 1313 题 960960 罚时,夺得冠军(第 11 名);
  • 厦门大学“点分治分点”代表队、福州大学“西南饺子馆”代表队, 1212 题 950950 罚时,以一模一样的罚时和题数,并列亚军(第 22 名);
  • 福建师范大学“夜幕降临”代表队、福建理工大学“福理重磅出击”代表队、福建农林大学“重生之我是懒狗”代表队, 1111 题 13101310 罚时,以一模一样的罚时和题数,并列殿军(第 44 名);
  • ……
  • 集美大学“抱歉,这没有集美”代表队, 999999 发代码提交却没有 11 发通过,最后以 00 题 00 罚时的成绩,惨遭爆零,取得全场最后一名。

前线记者贝贝发来报道。

已知所有队伍的通过题数、罚时,并且保证给出的顺序,符合 ACM 比赛最终榜单:按题数降序排列,当题数相同时,按照罚时升序排序

贝贝想知道,若将相同题数、相同罚时的队伍归为一类,最终共有多少类队伍?

输入格式

第一行包含一个整数 n(1≤n≤105)n(1≤n≤105) ,表示队伍的数量。

接下来的 nn 行,每行 22 个整数 ai,bi(0≤ai≤13,0≤bi≤2×103)ai​,bi​(0≤ai​≤13,0≤bi​≤2×103) ,分表表示第 ii 个队伍的通过题数和罚时。

保证给出的顺序符合 ACM 比赛的最终榜单。

输出格式

输出仅一行,包含一个整数,表示队伍的种类数量。

样例输入

7
13 960
12 950
12 950
11 1310
11 1310
11 1310
0 0

样例输出

4

说明

在样例中,共有 44 类队伍:

  • 1313 题 960960 罚时;
  • 1212 题 950950 罚时;
  • 1111 题 13101310 罚时;
  • 00 题 00 罚时。

运行限制

语言最大运行时间最大运行内存
C++1s256M
C1s256M
Java2s256M
Python33s256M
PyPy33s256M
Go3s256M
JavaScript3s256M

总通过次数: 1244  |  总提交次数: 1459  |  通过率: 85.3%

难度: 困难   标签: 双指针, 计数问题

算法思路

本问题要求统计 ACM 竞赛队伍中不同题数罚时组合的种类数量。输入数据已按题数降序、罚时升序排序,因此我们只需遍历一次队伍列表,通过比较相邻队伍的题数和罚时差异来计数类别。算法核心是 ​​相邻比较法​​,时间复杂度 O(n),空间复杂度 O(1)。

算法演示


graph TD
    A[开始] --> B[读取第一支队伍数据]
    B --> C[初始化计数器 ans=1]
    C --> D[遍历后续队伍]
    D --> E{当前队伍与上一支队伍<br>题数或罚时不同?}
    E -- 是 --> F[ans++]
    F --> G[更新上一支队伍数据]
    E -- 否 --> G
    G --> D
    D --> H[输出 ans]
    H --> I[结束]

完整代码(C++)

#include <cstdio>

int main() {
    int n;
    scanf("%d", &n);
    
    if (n == 0) {
        printf("0\n");
        return 0;
    }

    int prev_a, prev_b;
    scanf("%d %d", &prev_a, &prev_b);
    int ans = 1;

    for (int i = 1; i < n; i++) {
        int curr_a, curr_b;
        scanf("%d %d", &curr_a, &curr_b);
        
        if (curr_a != prev_a || curr_b != prev_b) {
            ans++;
        }
        
        prev_a = curr_a;
        prev_b = curr_b;
    }

    printf("%d\n", ans);
    return 0;
}

代码解析

  1. ​输入处理​​:

    • 使用 scanf 高效读取数据(比 cin 快 2-3 倍)

      1

    • 处理边界情况:n=0 时直接返回 0
  2. ​核心逻辑​​:

    
    
    	
    if (curr_a != prev_a || curr_b != prev_b) 
        ans++;

    • ​题数不同​​:必然是新类别(如 13 题 → 12 题)
    • ​题数相同但罚时不同​​:也是新类别(如 12 题/950 罚时 → 12 题/1310 罚时)
    • ​完全相同​​:跳过计数(如连续两支 12 题/950 罚时)
  3. ​数据更新​​:

    
    
    	
    prev_a = curr_a;
    prev_b = curr_b;

    • 无论是否新类别,都更新参考值为当前队伍,确保后续正确比较

实例验证

以样例输入为例:



7
13 960  // [1] ans=1(初始化)
12 950  // [2] 题数不同 → ans=2
12 950  // [3] 完全相同 → 跳过
11 1310 // [4] 题数不同 → ans=3
11 1310 // [5] 完全相同 → 跳过
11 1310 // [6] 完全相同 → 跳过
0 0     // [7] 题数不同 → ans=4

最终输出 4,符合预期。

注意事项

  1. ​输入顺序依赖​​:

    • 题目已保证输入按题数降序、罚时升序排序
    • 若未排序需先排序(时间复杂度 O(n log n))
  2. ​数据范围​​:

    • n ≤ 10⁵:必须用 O(n) 算法,暴力比对会超时
    • 罚时 ≤ 2000int 存储足够,无需 long
  3. ​边界情况​​:

    • 单支队伍(n=1):直接返回 1
    • 全相同队伍:返回 1
    • 全不同队伍:返回 n

测试点设计

​测试类型​输入数据预期输出验证目标
最小规模n=1[5,100]1边界处理
全相同队伍n=3[10,200],[10,200],[10,200]1相同类别识别
全不同队伍n=3[13,100],[12,200],[11,300]3差异识别
混合情况样例输入4综合逻辑验证
最大规模n=10⁵ 随机数据通过性能验证(<100ms)

优化建议

  1. ​输入输出加速​​:

    
    
    	
    ios::sync_with_stdio(false);
    cin.tie(0);

    • 使 cin 速度接近 scanf(需包含 <iostream>
  2. ​避免存储全量数据​​:

    • 当前算法仅存储上一支队伍数据,空间 O(1)
    • 存储全部数据会导致 O(n) 空间,不必要
  3. ​并行化优化​​:

    
    
    	
    #pragma omp parallel for reduction(+:ans)

    • 对超大规模数据(如 n>10⁷)可用 OpenMP 并行处理
    • 需编译选项 -fopenmp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鑫鑫向栄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值