1 条题解

  • 0
    @ 2026-6-19 10:30:10

    📝 题目大意

    NN 名考生,每人有数学成绩 AiA_i 和英语成绩 BiB_i。分三轮依次录取:先按数学成绩从高到低录 XX 人,再从未录取者中按英语成绩从高到低录 YY 人,最后从未录取者中按总分从高到低录 ZZ 人。同分时编号小的优先。输出所有录取者编号(升序)。

    💡 解题思路

    1. 题目分析N1000N \leq 1000,数据规模很小,直接模拟三轮排序筛选即可。关键约束是 1X+Y+ZN1 \leq X+Y+Z \leq N,保证录取人数合法,且每轮筛选必须跳过已录取的考生。

    2. 算法推导

      • 将学生信息(编号、数学、英语、总分)存入结构体数组 stu
      • 用一个 order 数组存储学生下标(00N1N-1),排序 order 而非直接排 stu,避免整体拷贝结构体。
      • 第一轮:按数学降序排序 order,同分按编号升序。遍历 order,将未录取的前 XX 人标记为 passed 并加入 qualified
      • 第二轮:按英语降序重新排序 order,同分按编号升序。同样跳过已录取者,取前 YY 人。
      • 第三轮:按总分降序重新排序 order,同分按编号升序。跳过已录取者,取前 ZZ 人。
      • 最后将 qualified 升序排序后输出。
    3. 边界与细节

      • X,Y,ZX, Y, Z 可能为 00(如样例 1 中 Y=0Y=0),此时对应轮次不录取任何人,cnt < 0 条件直接跳过循环。
      • 每轮遍历时需同时检查 i < Ncnt < 目标人数,防止越界或超出名额。
      • 排序比较器必须同时保证主关键字降序和次关键字(编号)升序,否则同分时选择错误。

    ⏱️ 复杂度分析

    • 时间复杂度O(NlogN)O(N \log N),三轮排序各 O(NlogN)O(N \log N),最后输出排序 O((X+Y+Z)log(X+Y+Z))O(NlogN)O((X+Y+Z) \log (X+Y+Z)) \subseteq O(N \log N)N1000N \leq 1000 完全可行。
    • 空间复杂度O(N)O(N),存储学生信息和辅助数组。

    💻 标准代码 (C++)

    #include<bits/stdc++.h>
    using namespace std;
    
    // 学生结构体:编号、数学成绩、英语成绩、总分
    struct Student {
        int id;
        int math;
        int eng;
        int total;
    };
    
    int main(){
        int N, X, Y, Z;
        cin >> N >> X >> Y >> Z;
        vector<Student> stu(N);
        // 读入编号和数学成绩
        for(int i = 0; i < N; i++) {
            stu[i].id = i + 1;
            cin >> stu[i].math;
        }
        // 读入英语成绩并计算总分
        for(int i = 0; i < N; i++) {
            cin >> stu[i].eng;
            stu[i].total = stu[i].math + stu[i].eng;
        }
    
        vector<bool> passed(N, false);   // 标记是否已被录取
        vector<int> qualified;           // 录取者编号列表
        vector<int> order(N);            // 排序用的下标数组
        for(int i = 0; i < N; i++) order[i] = i;
    
        // 第一轮:按数学成绩降序选 X 人,同分按编号升序
        sort(order.begin(), order.end(), [&](int i, int j){
            if(stu[i].math != stu[j].math) return stu[i].math > stu[j].math;
            return stu[i].id < stu[j].id;
        });
        int cnt = 0;
        for(int i = 0; i < N && cnt < X; i++) {
            int idx = order[i];
            if(!passed[idx]){
                passed[idx] = true;
                qualified.push_back(stu[idx].id);
                cnt++;
            }
        }
    
        // 第二轮:按英语成绩降序选 Y 人,同分按编号升序
        sort(order.begin(), order.end(), [&](int i, int j){
            if(stu[i].eng != stu[j].eng) return stu[i].eng > stu[j].eng;
            return stu[i].id < stu[j].id;
        });
        cnt = 0;
        for(int i = 0; i < N && cnt < Y; i++) {
            int idx = order[i];
            if(!passed[idx]){
                passed[idx] = true;
                qualified.push_back(stu[idx].id);
                cnt++;
            }
        }
    
        // 第三轮:按总分降序选 Z 人,同分按编号升序
        sort(order.begin(), order.end(), [&](int i, int j){
            if(stu[i].total != stu[j].total) return stu[i].total > stu[j].total;
            return stu[i].id < stu[j].id;
        });
        cnt = 0;
        for(int i = 0; i < N && cnt < Z; i++){
            int idx = order[i];
            if(!passed[idx]){
                passed[idx] = true;
                qualified.push_back(stu[idx].id);
                cnt++;
            }
        }
    
        // 按编号升序输出所有录取者
        sort(qualified.begin(), qualified.end());
        for(int id : qualified){
            cout << id << endl;
        }
        return 0;
    }
    
    • 1

    信息

    ID
    621
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者