点击知行合一Gesp>点击右上角“···”>设为星标🌟
大家好,我是黄老师。 曾任职多家国有大型科技公司,具有多年C/C++实战经验,打造过数百万用户规模的电子终端产品。目前是一名少儿C++编程业余讲师,毕竟CSP也自称非专业。😁
已经完成《GESP一级保命系列》专栏,《GESP二级编程保命-字符图形》专栏以及《GESP二级编程保命-暴力枚举》专栏、GESP三级编程-一维数组、GESP三级编程-字符串、GESP三级编程-进制转换、GESP三级编程-位运算、GESP三级编程-排序等等三级专题,供大家参考。
现在推出《GESP五级数论》专栏,并会分享相关实践经验,与同学们一起学习、进步。🚀
往期精选
GESP五级的核心就是“数据结构(链表)+ 基础算法(二分、贪心、分治、递归)+ 数论应用”。备考时,精力可以按 7:3 分配在“算法与数论”和“链表”上。考纲只要求链表,熟练掌握链表的选择、判断题目,满分是首要目标;初等数论与筛法:欧几里得算法、素数筛法、唯一分解定理等,务必掌握代码模版,灵活运用;四大核心算法包括贪心算法、二分算法、分治算法、递归算法!
五级
202403 成绩排序

洛谷网B3968

↑微信扫码注册信奥公开课小程序↑
五级
题解思路
1. 题目分析
核心任务:
有 N 名同学,每名有三科成绩(语文 c、数学 m、英语 e)
需要按以下规则从高到低排序:
比较总分(c + m + e),高者靠前
总分相同,比较语文+数学总分(c + m),高者靠前
仍相同,比较语文和数学的最高分 max(c, m),高者靠前
仍相同,则并列
输出要求:
按原始输入顺序(1~N)输出每位同学的排名
并列规则:x 人并列第 k 名,则下一名为 k+x 名(跳过 x-1 个名次)
样例验证:
略
2. 建模思路
数据结构:
struct stu {int c, m, e; // 三科成绩int tot; // 三科总分int cm_sum; // 语文+数学int cm_max; // 语文和数学的最高分int id; // 原始编号(从1开始)int rank; // 最终排名};
核心思想:
用结构体数组
a[10005]存储所有同学信息(从1开始使用)自定义
cmp函数实现三关键字降序排序排序后,从前到后扫描计算排名
用
ans[]数组按原始 id 存储排名,最后输出
3. 算法选择
算法:自定义排序 + 遍历计算排名
时间复杂度:O(N log N)
空间复杂度:O(N)
这道题目属于四级考察范畴,评级为弱五级吧
五级
题解代码
标准解法:结构体排序+自定义排序规则
#include<bits/stdc++.h>using namespace std;struct stu {int c, m, e; // c:语文, m:数学, e:英语int tot; // 三科总分int cm_sum; // 语数总分int cm_max; // 语数最高分int id; // 原始编号(从1开始)int rank; // 排名};stu a[10005]; // 全局数组,从1开始使用int ans[10005]; // 存储最终答案// 自定义比较函数boolcmp(const stu& x, const stu& y){// 规则1:比较总分,高者靠前if (x.tot != y.tot) return x.tot > y.tot;// 规则2:总分相同,比较语数总分,高者靠前if (x.cm_sum != y.cm_sum) return x.cm_sum > y.cm_sum;// 规则3:语数总分相同,比较语数最高分,高者靠前if (x.cm_max != y.cm_max) return x.cm_max > y.cm_max;// 托底规则:返回false表示x,y不用交换(本题全部相同,并列)return false;}intmain(){ios::sync_with_stdio(false);cin.tie(0);int N;cin >> N;// 读入数据(从1开始)for (int i = 1; i <= N; i++) {cin >> a[i].c >> a[i].m >> a[i].e;a[i].tot = a[i].c + a[i].m + a[i].e; // 计算总分a[i].cm_sum = a[i].c + a[i].m; // 计算语数总分a[i].cm_max = max(a[i].c, a[i].m); // 计算语数最高分a[i].id = i; // 记录原始编号}// 排序:从位置1开始,共N个元素sort(a + 1, a + N + 1, cmp);// 计算排名a[1].rank = 1; // 第一名排名为1for (int i = 2; i <= N; i++) {// 如果当前同学与前一同学的所有比较条件都相同if (a[i].tot == a[i-1].tot &&a[i].cm_sum == a[i-1].cm_sum &&a[i].cm_max == a[i-1].cm_max) {// 并列,排名相同a[i].rank = a[i-1].rank;} else {// 不并列,新排名 = 当前位置a[i].rank = i;}}// 按原始顺序输出for (int i = 1; i <= N; i++) {// 将排名存入对应原始id的位置ans[a[i].id] = a[i].rank;}// 按原始id顺序(1~N)输出排名for (int i = 1; i <= N; i++) {cout << ans[i] << '\n';}return 0;}
GESP C++四级真题 | 202603礼盒排序(结构体+排序)GESP C++四级真题 | 202512 优先购买(排序、结构体)
↑微信扫码注册信奥公开课小程序↑

加 VX 联系年卡办理与备考资料领取
五级
STL题解参考
使用优先队列 priority_queue 自动排序,需要 < 运算符重载。
#include<bits/stdc++.h>using namespace std;struct stu {int c, m, e;int tot, cm_sum, cm_max;int id, rank;// 优先队列的排序(注意:与sort相反)bool operator<(const stu& other) const {if (tot != other.tot) return tot < other.tot;if (cm_sum != other.cm_sum) return cm_sum < other.cm_sum;return cm_max < other.cm_max;}};priority_queue<stu> pq;stu a[10005];int ans[10005];intmain(){ios::sync_with_stdio(false);cin.tie(0);int N; cin >> N;for (int i = 1; i <= N; i++) {cin >> a[i].c >> a[i].m >> a[i].e;a[i].tot = a[i].c + a[i].m + a[i].e;a[i].cm_sum = a[i].c + a[i].m;a[i].cm_max = max(a[i].c, a[i].m);a[i].id = i;pq.push(a[i]);}int rank = 1;while (!pq.empty()) {stu cur = pq.top();pq.pop();// 找并列vector<int> same;same.push_back(cur.id);while (!pq.empty()) {stu nxt = pq.top();if (nxt.tot == cur.tot &&nxt.cm_sum == cur.cm_sum &&nxt.cm_max == cur.cm_max) {pq.pop();same.push_back(nxt.id);} else {break;}}for (int id : same) {ans[id] = rank;}rank += same.size();}for (int i = 1; i <= N; i++) {cout << ans[i] << '\n';}return 0;}

加 VX 联系年卡办理与备考资料领取