目录
P14795 [JOI 2026 二次预选] 分班 / Class Division




题目描述
JOI 高校的一年级共有 N N N 人,并被编号为从 1 1 1 到 N N N。
某天,一年级的 N N N 人参加了考试。学生 i i i( 1 ≤ i ≤ N 1 \le i \le N 1≤i≤N)的得分为 A i A_i Ai 分。这里, N N N 人并不是都取得了相同的分数。
根据这次考试的成绩来决定明年的分班。具体来说,选择一个整数 x x x,将 N N N 名学生分成两个班:得分在 x x x 分以上(含 x x x 分)的学生进入升学班,得分低于 x x x 分的学生进入普通班。
在此,要求每个班都至少有 1 1 1 名学生,并且选择一种分法,使升学班的人数与普通班的人数之差最小。进一步地,如果满足条件的分法有多个,则在其中选择升学班人数最少的分法。
给定学生人数以及每位学生的得分,编写程序求出升学班学生得分的最低分。
输入格式
输入按以下格式给出。
N N N
A 1 A 2 ... A N A_1\ \ A_2\ \ \dots\ \ A_N A1 A2 ... AN
输出格式
输出一行:升学班学生得分的最低分。
输入输出样例 #1
输入 #1
3
1000 500 800
输出 #1
1000
输入输出样例 #2
输入 #2
6
100 75 41 75 13 89
输出 #2
89
输入输出样例 #3
输入 #3
6
20 25 12 7 13 16
输出 #3
16
输入输出样例 #4
输入 #4
8
364353982 103422534 437367896 91518637 364353982 221490368 437367896 103422534
输出 #4
364353982
说明/提示
样例解释
样例 1 1 1 解释
例如,令 x = 900 x = 900 x=900,则学生 1 1 1 被分到升学班,学生 2 , 3 2, 3 2,3 被分到普通班。
另一种可能的分班方式是,将学生 1 , 3 1, 3 1,3 分到升学班,将学生 2 2 2 分到普通班。比如令 x = 800 x = 800 x=800 就可以实现这一点。
这两种分法中,升学班人数与普通班人数之差都为 1 1 1。因此,会选择升学班人数最少的前一种分法。此时,升学班学生得分的最低分是 1 000 1\,000 1000 分。
该输入样例满足所有子任务的约束。
样例 2 解释
令 x = 89 x = 89 x=89,则学生 1 , 6 1, 6 1,6 被分到升学班,学生 2 , 3 , 4 , 5 2, 3, 4, 5 2,3,4,5 被分到普通班。此时升学班学生得分的最低分为 89 89 89 分。
该输入样例满足子任务 4 的约束。
样例 3 3 3 解释
该输入样例满足子任务 3, 4 的约束。
样例 4 4 4 解释
该输入样例满足子任务 4 的约束。
约束
- 2 ≤ N ≤ 500 000 2 \le N \le 500\,000 2≤N≤500000。
- 1 ≤ A i ≤ 10 9 1 \le A_i \le 10^9 1≤Ai≤109( 1 ≤ i ≤ N 1 \le i \le N 1≤i≤N)。
- 存在 i , j i, j i,j( 1 ≤ i < j ≤ N 1 \le i < j \le N 1≤i<j≤N)使得 A i ≠ A j A_i \ne A_j Ai=Aj。
- 输入的值均为整数。
子任务
- (20 pts) \text{(20 pts)} (20 pts): N = 3 N = 3 N=3。
- (20 pts) \text{(20 pts)} (20 pts): A i A_i Ai 为 500 , 800 , 1 000 500, 800, 1\,000 500,800,1000 之一( 1 ≤ i ≤ N 1 \le i \le N 1≤i≤N)。
- (20 pts) \text{(20 pts)} (20 pts): A i ≠ A j A_i \ne A_j Ai=Aj( 1 ≤ i < j ≤ N 1 \le i < j \le N 1≤i<j≤N)。
- (40 pts) \text{(40 pts)} (40 pts):无额外约束。
分析
我们已经知道, x x x 是 a i a_i ai 中的一个,于是,我们要从 a i a_i ai 开始找。
排序
这道题,因为要从 a i a_i ai 里面找,为了更好计算,我们要对他进行排序。
cpp
#include<algorithm>//所需头文件
sort(a+1,a+n+1);//用函数
重复情况
这个题有重复成绩。因为样例二就能知道。
6
100 75 41 75 13 89
我们从后面枚举直接跳过就行。
cpp
int j=i;//定位
while(i>=1&&a[i]==a[j]) i--;//查找重复
找id
这个题我们要用两个变量用来判断最小,和找出最小分数编号 m i n n minn minn 和 i d id id ,从后挨个找就行。
cpp
if(minn>abs(n-i*2)){
id=i;
minn=abs(n-i*2);
}
最后输出
输出时要输出 i d id id 但 i d id id 还要加 1 1 1 于是 cout<<a[id+1]; 。
AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
int a[500005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
int i=n,minn=1e9,id=0;
while(i>=1){
int j=i;
while(i>=1&&a[i]==a[j]) i--;
if(minn>abs(n-i*2)){
id=i;
minn=abs(n-i*2);
}
}
cout<<a[id+1];
return 0;
}