【天梯赛L1-7】天梯赛的善良 - 最小/最大能力值统计

一、题目描述

天梯赛命题组需要统计所有参赛学生的最小能力值最大能力值,并统计具有这两个能力值的学生人数。
输入格式

  • 第一行:学生总数 N(≤ 2×10⁴)

  • 第二行:N 个不超过 10⁶ 的正整数(能力值)

输出格式

  • 第一行:最小能力值 + 该能力值人数

  • 第二行:最大能力值 + 该能力值人数

示例输入

复制

10
86 75 233 888 666 75 886 888 75 666

示例输出

复制

75 3
888 2

二、题目分析
  1. 核心需求

    • 找到数组中的最小值最大值

    • 统计这两个值的出现次数

  2. 关键点

    • 数据范围较大(N ≤ 2×10⁴),需用O(n)或O(nlogn)算法。

    • 最小值/最大值可能有重复值,需正确计数。

    • 暴力法(命题组看了会沉默):

      • 直接遍历数组,记录最小值和最大值,再数一遍有几个。

      • 时间复杂度:O(n)(但写起来有点啰嗦)。

    • 排序法(我选择偷懒):

      • 先排序,最小值在开头,最大值在结尾。

      • 然后数数开头有多少个一样的,结尾有多少个一样的。

      • 时间复杂度:O(nlogn)(但代码短,适合我这种懒人)。

    • 我选排序法!(因为STL的 sort 太好用了)


三、代码实现

#include<bits/stdc++.h>
using namespace std;
int main() {
    int a;
    cin >> a;
    int C[20005];
    for (int i = 1; i <= a; i++) {
        cin >> C[i];
    }
    sort(C + 1, C + 1 + a);  // 升序排序
    int numa = 1, numb = 1;   // 初始化最小/最大值的计数
    // 统计最小值出现次数
    for (int i = 1; i <= a; i++) {
        if (C[i] == C[i + 1]) numa++;
        else break;
    }
    // 统计最大值出现次数
    for (int i = a; i >= 0; i--) {
        if (C[i] == C[i - 1]) numb++;
        else break;
    }
    // 输出结果
    cout << C[1] << " " << numa << endl;
    cout << C[a] << " " << numb << endl;
    return 0;
}

四、代码解析
  1. 输入处理

    • 用数组 C 存储所有学生的能力值,下标从1开始(符合题目习惯)。

  2. 排序优化

    • 调用 sort(C+1, C+1+a) 对能力值升序排序,使得最小值为 C[1],最大值为 C[a]

  3. 统计最小值次数

    • 从前往后遍历,若当前值等于下一个值(C[i] == C[i+1]),则计数 numa++,否则退出循环。

  4. 统计最大值次数

    • 从后往前遍历,若当前值等于前一个值(C[i] == C[i-1]),则计数 numb++,否则退出循环。

  5. 输出结果

    • 直接取 C[1] 和 C[a] 作为最小/最大值,并输出对应的计数。


五、总结

本题通过排序+双指针计数巧妙解决了最小/最大值统计问题,适合初学者练习数组操作和边界处理。命题组的“善良”在于数据范围友好,允许使用排序解法。

关键点:排序后的首尾元素即是最值,重复值需正确计数!

### 天梯赛 L1-016 题目解析 天梯赛 L1-016 的题目名称为 **“凑零钱”**,其核心在于通过给定的一组硬币面额以及目标金额,计算最少需要多少枚硬币来组成该目标金额。此问题属于经典的动态规划问题之一。 #### 动态规划解法分析 对于此类问题,可以采用动态规划的思想解决。定义 `dp[i]` 表示凑成金额 `i` 所需的最小硬币数量,则状态转移方程如下: \[ dp[j] = \min(dp[j], dp[j - coins[k]] + 1) \] 其中 \( j \geq coins[k] \),\( k \) 是硬币种类索引[^1]。 初始条件设置为: - 当金额为 0 时,所需硬币数为 0,即 \( dp[0] = 0 \)。 - 对于其他金额初始化为正无穷大(表示不可达),以便后续更新最优。 最终答案存储在数组的最后一项 \( dp[target] \) 中。如果无法凑出目标金额,则返回 `-1`。 以下是基于上述思路的 C++ 实现代码: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; const int INF = 1e9; // 定义一个较大的数作为正无穷 signed main(){ int target; cin >> target; // 输入目标金额 vector<int> coins = {1, 2, 5}; // 假设硬币面额为 1, 2, 5 (可根据实际输入调整) vector<int> dp(target + 1, INF); // 初始化 dp 数组 dp[0] = 0; // 初始条件 for(auto coin : coins){ for(int j = coin; j <= target; ++j){ if(dp[j - coin] != INF){ // 如果前一项可达 dp[j] = min(dp[j], dp[j - coin] + 1); } } } if(dp[target] == INF){ cout << "-1"; // 若仍为 INF,说明无法凑出目标金额 }else{ cout << dp[target]; // 输出最少硬币数 } } ``` 以上代码实现了动态规划的核心逻辑,并能够处理多种不同的硬币组合情况。需要注意的是,在实际比赛中可能还需要考虑更多边界条件或者优化性能以适应更大的数据规模。 --- #### 时间复杂度与空间复杂度 时间复杂度主要由两层循环决定,假设硬币总数为 \( m \),最大金额为 \( n \),则总的时间复杂度为 \( O(m \times n) \)。而由于只维护了一个一维数组用于记录中间结果,因此空间复杂度为 \( O(n) \)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值