某比赛已经进入了淘汰赛阶段,已知共有n名选手参与了此阶段比赛,他们的得分分别是a_1,a_2….a_n,小美作为比赛的裁判希望设定一个分数线m,使得所有分数大于m的选手晋级,其他人淘汰。
但是为了保护粉丝脆弱的心脏,小美希望晋级和淘汰的人数均在[x,y]之间。
显然这个m有可能是不存在的,也有可能存在多个m,如果不存在,请你输出-1,如果存在多个,请你输出符合条件的最低的分数线。
数据范围:
,
进阶:时间复杂度
,空间复杂度%5C)
某比赛已经进入了淘汰赛阶段,已知共有n名选手参与了此阶段比赛,他们的得分分别是a_1,a_2….a_n,小美作为比赛的裁判希望设定一个分数线m,使得所有分数大于m的选手晋级,其他人淘汰。
但是为了保护粉丝脆弱的心脏,小美希望晋级和淘汰的人数均在[x,y]之间。
输入第一行仅包含三个正整数n,x,y,分别表示参赛的人数和晋级淘汰人数区间。(1<=n<=50000,1<=x,y<=n)
输入第二行包含n个整数,中间用空格隔开,表示从1号选手到n号选手的成绩。(1<=|a_i|<=1000)
输出仅包含一个整数,如果不存在这样的m,则输出-1,否则输出符合条件的最小的值。
6 2 3 1 2 3 4 5 6
3
n, x, y = map(int, input().strip().split()) a = list(map(int, input().strip().split())) a.sort() # a.reverse() flag = 0 for i in range(x, y+1): if a[i] != a[i-1] and len(a)-i <= y: flag = 1 print(a[i-1]) break if flag == 0: print(-1)
对数据进行排序,排完了按需要的数量输出就行了
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
class Solution{
public:
int sore(int n, int x, int y, vector<int> nums){
if(2*x > n || n > 2*y)return -1;
sort(nums.begin(), nums.end());
if(x+y >= n){
return nums[x-1];
}else{
return nums[n-y];
}
}
};
int main(){
int n, x, y;
cin>>n>>x>>y;
vector<int> nums(n);
for(int i = 0; i<n; i++){
int temp;
cin>>temp;
nums[i] = temp;
}
int res = Solution().sore(n, x, y, nums);
cout<<res;
return 0;
} #!/usr/bin/python # _*_ coding:utf-8 _*_ # Author:xiaoshubiao # Time : 2021/3/13 10:49 n, x, y = [int(s) for s in input().split()] l = [int(s) for s in input().split()] # 对成绩进行排序 l.sort() # 临时变量ind ind = x # 默认输出min min = -1 # 从x的最小值开始一直遍历到y,判断淘汰人数和晋级人数都在x,y的区间内 # 假设ind为淘汰人数 # ind 淘汰人数 # n-ind 就是晋级人数 while ind <= y: # 1、判断人数是否在区间内 # 2、判断当前分数线,是否存在两个人成绩是一样的 if x <= n - ind <= y and l[ind - 1] != l[ind]: # 不一样则满足输出,一样则不满足条件 # 例如 输入6 2 3 1 2 3 3 5 6 此时输出的结果应该是-1 而不是3 因为两个人的成绩是一样的 min = l[ind - 1] break ind += 1 print(min)
emmm,也发一波自己的代码吧 应该挺简单易懂的
import java.util.Arrays;
import java.util.Scanner;
/**
* 美团校招 第10场 第1题
*/
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int x = in.nextInt();
int y = in.nextInt();
int[] score = new int[n];
for (int i = 0; i < n; i++) {
score[i] = in.nextInt();
}
/**
* 符合条件的最低分数线 -> 过线的人多 -> 使用人数限制最大值 y作为过线人数 -> 判断剩下的人数 是否在[x,y]区间 ->
* 如果在 直接返回
* 如果不在
* 如果人数少于x 则直接找到分数最低的第x个人即可
* 如果人数大于y 则证明找不到一个分数线满足条件
*/
// 对成绩排序
Arrays.sort(score);
// 没过线的人数
int notOk = n - y;
if (notOk > y){
System.out.println(-1);
}else if (notOk >= x && notOk <= y){
System.out.println(score[n-y-1]);
}else{
System.out.println(score[x-1]);
}
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] params = br.readLine().trim().split(" ");
int n = Integer.parseInt(params[0]);
int x = Integer.parseInt(params[1]);
int y = Integer.parseInt(params[2]);
String[] strArr = br.readLine().trim().split(" ");
int[] scores = new int[n];
for(int i = 0; i < n; i++) scores[i] = Integer.parseInt(strArr[i]);
Arrays.sort(scores);
// 每位选手要么就晋级,要么就淘汰,是互斥的
int m = -1;
int i = 0;
int count = n - 1;
for(i = 0; i < n; i++){
m = scores[i];
if(count >= x && count <= y && n - count >= x && n - count <= y){
// 检查一下是不是真的能晋级count人
if(judge(scores, i, m, count)) {
break;
}else
m = -1;
}else{
m = -1;
count --;
}
}
System.out.println(m);
}
private static boolean judge(int[] scores, int start, int m, int target) {
start ++;
if(start == scores.length) return false;
while(start < scores.length){
if(scores[start] == m) return false;
start ++;
}
return true;
}
} 一开始想复杂了,惯性的想到二分查m,结果有些条件不会判断...
后来,思路写着写着发现,直接遍历不就行了吗😕
我们可以先从小到大排序,然后遍历淘汰的人数b,范围是[1,n]
对于每个b,我们可以算出晋级人数a = n-b,比较a和b是否在范围。如果符合条件,这个b就是符合条件的最少淘汰人数,对应这个m的最低分数线。最低分数线意味着淘汰最少的人。
以下是我的临场笔记思路...
/*
二分找m
1 2 3 4 5 6 [l,r]
m = 3
O(n)算出晋级的人a, 淘汰的人b
如果a,b都在区间,m往左移动找到最低值
m越大,a越小
如果a<l,表示m太大了,m往左移动
如果a>r,表示m太小了,m往右移动
如果a在区间,b不在区间:
如果a在区间,b<l,表示晋级的人多了,淘汰的人少了,m往右移动
如果a在区间,b>r,m往左移动
现在关键是,什么情况下m不存在
a的取值是[0,n],b对应为n-a
需要同时满足:a在[l,r]且b在[l,r]
b从小到大遍历,就是m的最低分数线...
最低分数线意味着淘汰人最少,b在满足条件情况下的最小值对应的分数就是m...
1 2 3 4 5 6
小于等于m淘汰
*/
#include
using namespace std;
int main()
{
int n, l, r;
scanf("%d%d%d",&n,&l,&r);
int arr[50050];
for(int i = 0;i < n;i++)
{
scanf("%d",&arr[i]);
}
sort(arr,arr+n);
//遍历淘汰人数
int m = -1;
for(int i = 1;i <= n;i++)
{
int j = n-i; //晋级人数
if(i >= l && i = l && j <= r)
{
//算出m
m = arr[i-1];
break;
}
}
cout<<m<<endl;
return 0;
}
import java.util.Scanner;
import java.util.Arrays;
public class Main{
public static void main(String[] args){
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
int x=scan.nextInt();
int y=scan.nextInt();
int[] score=new int[n];
for(int i=0;i<n;i++){
score[i]=scan.nextInt();
}
System.out.println(new Main().resM(score,x,y));
}
public int resM(int[] array,int x,int y){
if(array.length==0 ||array.length<x)
return -1;
if(x>=y)
return -1;
int len=array.length;
int X=x;
int Y=len-x;
if(new Main().minPre(x,len-y))
X=len-y;
if(new Main().minPre(y,len-x))
Y=y;
if(X>Y)
return -1;
Arrays.sort(array);
if(len<X)
return -1;
return array[X-1];
}
public boolean minPre(int x,int y){
if(x<y)
return true;
return false;
}
} 来个短点的
n, x, y = map(int, input().split())
arr = list(map(int, input().split()))
arr.sort()
if y * 2 < n:
print(-1)
else:
i = n - y - 1
if i + 1 < x:
i = x - 1
print(arr[i])
/*
感谢 @地大小菜 的建议,对原始回答进行了修改
n个选手成绩,要想晋级和淘汰的人数均在[x,y]之间,
对成绩排序,然后输出最低位合适的位置即可,对于合适位置的判断分以下几种情况
1.x>n/2, 如n=100,[59,60]
晋级和淘汰都大于58,总人数超过100,不成立,输出-1
2.y<n/2+n%2, 如n=100,[2,4]
晋级和淘汰人数都小于5,总人数小于10,则小于100,不成立,输出-1
特殊情况,如n=101,[49,50]
晋级人数和淘汰人数都小于等于50,总人数小于等于100<n=101,不成立,输出-1,
如果y1=y+1=50+1,则,ans=49,成立
3.符合条件的最低的分数线
3.1以x为基准
如n=100,[49,55]
如果选择第x=49个,那么前49,后51,成立,由于是升序(已排序),
所以第49个必定最小
3.2以y为基准
如n=100,[5,55]
如果选择第x=5个,那么前5,后95,95>y=55,不成立
分析:选择一个位置m,使得分数低的人数nums_low和分数高的人数nums_high,
都在[x,y]区间,
必有 x<m<y && x<n-m<y ,n-m代表晋级人数
又因为选择最小分数,所以,位置max(x,n-y)为答案
即 m=y; while(m>=x) if(suit(m)) m--;
//suit(m)代表m的位置满足
x<m<y && x<n-m<y
4.特例 存在分数相等的情况
例如
6 2 3
1 2 2 2 3 3
选择2就会分成【4,2】,与题意不符
对于
6 2 3
1 2 2 3 3 3
选择2就可以
对于这种情况需要从非特例方案选择出位置pos, 然后往后搜寻,
找出第一个与pos位置值不一样的位置,
得到前后两端元素个数,判断是否满足题目要求即可
*/
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int main(){
int n, x, y;
scanf("%d %d %d", &n, &x, &y);
int num, ans=0;
int nums[50005];
for(int i=0; i<n; i++){
scanf("%d", &num);
nums[i]=num;
}
sort(nums, nums+n);
if(x>n/2|| y<n/2+n%2){
ans=-1;
}else{
int less=n-y;
less=less>x?less:x;
ans=nums[less-1];//从0开始
int i;
for(i=less; i<n; i++){
if(nums[i]!=ans){
break; } } if(n-i>=x&& n-i<=y&&i>=x&& i<=y){ }else{ ans=-1; }
}
cout<<ans;
return 0;
}
二分优化
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50005;
int a[N];
int main() {
int n, x, y;
cin >> n >> x >> y;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
sort(a, a + n);
auto check = [&](int mid) {
auto it = (upper_bound(a, a + n, mid) - a);
if (n - it >= x && n - it <= y && it >= x && it <= y) {
return true;
}
return false;
};
for (int i = 1; i <= 1000; ++i) {
if (check(i)) {
cout << i << endl;
return 0;
}
}
cout << -1 << endl;
return 0;
}
public class Main {
public static void main(String[] args) {
int score = new Main().score();
System.out.println(score);
}
public int score(){
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int x=scanner.nextInt();
int y=scanner.nextInt();
int[] i2 = new int[n];
for(int i=0;i<n;i++)
i2[i]=scanner.nextInt();
Arrays.sort(i2);
if(y>=n)
return -1;
return x<n-y?i2[n-y-1]:i2[x-1]; //贪心
}
} import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int m = -1;
int[] nums = new int[n];
for(int i = 0;i < n;i++)
nums[i] = sc.nextInt();
if(n == 1){
System.out.println(-1);
return;
}
if(2 * x > n){
System.out.println(-1);
return;
}
Arrays.sort(nums);
m = nums[n - y - 1];
int index = n - y - 1;
while(index + 1 < x){
index++;
m = nums[index];
}
System.out.println(m);
}
} #include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
int main(){
int n,x,y;
cin>>n>>x>>y;
vector<int> a(n);
map<int,int> data;
for(int i=0;i<n;i++){
cin>>a[i];
data[a[i]]++;
}
//构建两个固定的滑动窗口,左窗口为[x-1,y-1],右窗口为[n-y-1,n-x-1],
//右窗口原本是[n-y,n-x],但根据题目要求(分数线要大于m),
//所以取分数线的点要左移一位
if(n-y-1>(y-1)|| n-x-1<(x-1)){
cout<<-1;
return 0;
}
//在原有窗口的数字上加一,为后面比较数量做准备
int min1=max(x,n-y);
int max1=min(n-x,y);
int temp=0;
for(auto it = data.begin();it!=data.end();it++){
temp+=it->second;
if(temp>=min1&&temp<<max1){
cout<<it->first;
return 0;
}
}
cout<<-1;
return 0;
}