牛客NC16625 [NOIP2009]分数线划定(排序)
题目描述
世博会志愿者的选拔工作正在 A 市如火如荼地进行。为了选拔最合适的人才,A 市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。
面试分数线根据计划录取人数的 150150%150 划定,即如果计划录取 mmm 名志愿者,则面试分数线为第 ⌊m×1.5⌋\lfloor m \times 1.5 \rfloor⌊m×1.5⌋ 名选手的笔试成绩。
最终进入面试的选手为 所有笔试成绩不低于面试分数线 的选手。
请你编写程序,划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。
输入格式
第一行两个整数 n,mn, mn,m,用空格隔开,表示报名参加笔试的选手总数和计划录取的人数。
接下来 nnn 行,每行两个整数 k,sk, sk,s,用空格隔开,表示选手的报名号 kkk 和笔试成绩 sss。
输出格式
第一行输出两个整数,分别表示面试分数线和进入面试的实际人数。
接下来每行输出两个整数,表示进入面试的选手的报名号和成绩。
输出顺序按成绩从高到低;
如果成绩相同,则按报名号从小到大。
样例输入
6 3
9848 90
6731 88
1422 95
7483 84
8805 95
4162 88
样例输出
88 5
1422 95
8805 95
9848 90
4162 88
6731 88
样例说明
样例解释:
计划录取人数为 333,因此计算面试线位置为 ⌊3×1.5⌋=4\lfloor 3 \times 1.5 \rfloor = 4⌊3×1.5⌋=4。
排序后前 444 名的分数依次为:95、95、90、8895、95、90、8895、95、90、88,因此面试分数线为 888888。
所有分数 ≥88≥ 88≥88 的选手均进入面试,最终人数为 555。
数据范围:
-
5≤n≤50005 \leq n \leq 50005≤n≤5000
-
3≤m≤n3 \leq m \leq n3≤m≤n
-
1000≤k≤99991000 \leq k \leq 99991000≤k≤9999
-
1≤s≤1001 \leq s \leq 1001≤s≤100
-
数据保证报名号各不相同,且 ⌊m×1.5⌋≤n\lfloor m \times 1.5 \rfloor \leq n⌊m×1.5⌋≤n。
提交链接
分数线划定
思路分析
🧠 题解思路(基于数组 + 排序实现)
本题的目标是选出所有成绩不低于“面试分数线”的选手。题目的关键点在于:
- 面试分数线是按照计划录取人数的 1.51.51.5 倍来决定的,即:
分数线排名=⌊m×1.5⌋\text{分数线排名} = \left\lfloor m \times 1.5 \right\rfloor 分数线排名=⌊m×1.5⌋
- 所有成绩 ≥\geq≥ 分数线的选手都可进入面试。
- 输出要求:成绩高的在前,如果成绩相同,报名号小的在前。
✅ 解题步骤
Step 1:输入与数据结构
使用 pair<int, int>
存储每个选手的报名号和成绩,方便排序和处理。
pair<int, int> p[5009]; // p[i].first = 报名号,p[i].second = 成绩
Step 2:排序规则
用 sort 函数配合 Lambda 表达式排序,规则如下:
-
成绩从高到低排序;
-
如果成绩相同,则报名号从小到大排序。
sort(p + 1, p + n + 1, [](const pi &x, const pi &y) {if (x.second == y.second) return x.first < y.first;return x.second > y.second;
});
Step 3:确定分数线
找到第 ⌊m×1.5⌋\left\lfloor m \times 1.5 \right\rfloor⌊m×1.5⌋ 名的选手的成绩作为面试分数线。
int score = p[(int)(m * 1.5)].second;
⚠️ 注意:数组从下标 1 开始,所以直接访问下标 (int)(m * 1.5)
即可。
Step 4:统计符合条件的选手
遍历前 nnn 名,统计所有成绩 ≥\geq≥ 分数线的选手人数 cntcntcnt。
int cnt = 0;
for (int i = 1; i <= n; i++) {if (p[i].second >= score) cnt++;
}
Step 5:输出结果
第一行输出面试分数线和实际进入面试的人数;
接下来的每行输出报名号和成绩(已排好序):
cout << score << " " << cnt << endl;
for (int i = 1; i <= cnt; i++) {cout << p[i].first << " " << p[i].second << endl;
}
📌 时间复杂度分析
-
排序:O(nlogn)O(n \log n)O(nlogn)
-
遍历:O(n)O(n)O(n)
因此总时间复杂度为:O(nlogn)O(nlogn)O(nlogn)
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int , int>pi;int n , m;
pair<int , int>p[5009];int main()
{cin >> n >> m; //总人数n 计划录取m人for(int i = 1; i <= n; i++){cin >> p[i].first >> p[i].second; //报名号k 笔试成绩s}//成绩从大到小排序 成绩一样报名号从小到大(输出)sort(p + 1 , p + n + 1 , [](const pi &x , const pi &y){if(x.second == y.second)return x.first < y.first; return x.second > y.second;});int score = p[(int)(m * 1.5)].second; //向下取整 面试分数线int cnt = 0;for(int i = 1; i <= n; i++){if(p[i].second >= score)cnt++;}cout << score << " " << cnt << endl;for(int i = 1; i <= cnt; i++){cout << p[i].first << " " << p[i].second << endl;}return 0;
}