首页 > 试题广场 >

淘汰分数

[编程题]淘汰分数
  • 热度指数:29692 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

某比赛已经进入了淘汰赛阶段,已知共有n名选手参与了此阶段比赛,他们的得分分别是a_1,a_2….a_n,小美作为比赛的裁判希望设定一个分数线m,使得所有分数大于m的选手晋级,其他人淘汰。

但是为了保护粉丝脆弱的心脏,小美希望晋级和淘汰的人数均在[x,y]之间。

显然这个m有可能是不存在的,也有可能存在多个m,如果不存在,请你输出-1,如果存在多个,请你输出符合条件的最低的分数线。

数据范围:
进阶:时间复杂度,空间复杂度

输入描述:

输入第一行仅包含三个正整数n,x,y,分别表示参赛的人数和晋级淘汰人数区间。(1<=n<=50000,1<=x,y<=n)

输入第二行包含n个整数,中间用空格隔开,表示从1号选手到n号选手的成绩。(1<=|a_i|<=1000)



输出描述:

输出仅包含一个整数,如果不存在这样的m,则输出-1,否则输出符合条件的最小的值。

示例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)

发表于 2021-03-17 21:19:17 回复(5)
对数据进行排序,排完了按需要的数量输出就行了
#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;
}

发表于 2021-03-13 00:01:31 回复(8)
#!/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)
按照正常情况是会存在成绩相同的情况,所以下面的很多答案应该是不对的,可以拿这个例子试一下:
6 2 3 
1 2 3 3 5 6 
结果应该是-1 而不是3
编辑于 2021-03-13 12:13:09 回复(6)

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]);
        }
    }
}
发表于 2021-03-17 20:44:19 回复(12)
const [n,x,y] = readline().split(" ").map(Number);
let grades = readline().split(" ").map(Number).sort((a,b)=>{
    return a-b;
});
console.log(getMin());
function getMin(){
    if(n<x*2 || n> y*2) return -1;
    let min = n>x+y?n-y:x;
    while(grades[min]==grades[min+1]) min++;
    if(n-min<x)return -1;
    return grades[min-1]
}
**的解答...
发表于 2021-08-28 13:35:00 回复(7)
测试用例没考虑全,这个题贪心应该是不行的。稍微暴力一点,先对得分进行升序排列,然后从小到大遍历分数线的可能性。由于至少会淘汰一个人,因此初始化晋级的人数为count=n-1,此时淘汰的人数为n-count,从scores[0]开始作为分数线。
在遍历的过程中,对于考虑某个分数scores[i]是否可以作为分数线时,有如下两种情况:
(1) 晋级人数count和淘汰人数n-count都在区间[x,y]内。当然,就算满足这一点,由于还没有见到排在后面的分数,我们也无法得知后面的分数是否都是大于scores[i],所以我们需要检查一下这一点,如果是就输出这个分数作为分数线,如果不是,那分数线m还是为-1,需要继续遍历下一个分数。
(2) 如果不满足(1)那就直接遍历下一个分数,晋级人数count-1,分数线m仍然为-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;
    }
}


编辑于 2021-03-07 12:17:24 回复(9)

一开始想复杂了,惯性的想到二分查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;
}
发表于 2021-03-15 20:20:27 回复(4)
由于是要输出最低分数线,先对所有分数进行排序,所以可以设定一个标记,从数组x的位置增加,看左右人数是否满足条件
n,x,y=list(map(int,input().split()))
nums=list(map(int,input().split()))
nums.sort()
l=x-1
while n-l-1>y and l<y:
    l+=1
if l==y:
    print(-1)
else:
    print(nums[l])


发表于 2021-03-12 15:21:23 回复(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;
    }
}

发表于 2021-03-09 21:11:50 回复(1)

来个短点的

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])
发表于 2023-03-18 03:14:24 回复(1)
/*
感谢 @地大小菜 的建议,对原始回答进行了修改
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;
}

编辑于 2021-03-15 09:33:35 回复(1)
import java.util.Arrays;
import java.util.Scanner;
 
/**
 * 美团校招 第10场 第1题
 */
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[] nums=new int[n];
        for(int i=0;i<n;i++){
            nums[i]=sc.nextInt();
        }
        sc.close();
        Arrays.sort(nums);
        for(int i=0;i<n;i++){
            int position = findPosition(nums, nums[i]);
            if(x<=position&&y>=position&&(n-x)>=position&&(n-y)<=position){
                System.out.println(nums[i]);
                return;
            }
        }
        System.out.println(-1);
    }
//二分查找右边界(右边界定义:返回的数组下标值为小于等于target的个数),本题中返回数组下标值即为淘汰的人数
    private static int findPosition(int[] nums,int target){
        if(nums.length==0) return -1;
        int left =0;
        int right=nums.length;
        while(left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                left=mid+1;
            }else if(nums[mid]<target){
                left=mid+1;
            }else if(nums[mid]>target){
                right=mid;
            }
        }
        return left;
    }
}

发表于 2022-04-01 11:32:01 回复(2)

二分优化

#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;
}
发表于 2021-03-07 22:01:21 回复(0)
n, x, y = [int(i) for i in input().split()]
score = [int(i) for i in input().split()]
score.sort()
for i in range(x, y+1):
    if n-i >= x and n-i <= y:
        result = score[i-1]
        break
print(result)
发表于 2021-03-01 23:52:58 回复(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];  //贪心
    }
}

发表于 2021-02-27 15:24:56 回复(9)
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>

using namespace std;

int main(){
    int n, x, y;
    int result = -1;
    
    cin >> n >> x >> y;
    
    unordered_map<int, int> hashmap;
    int tmp;
    while(cin >> tmp){
        ++hashmap[tmp];
    }
    
    vector<int> count;
    vector<int> num;
    
    for(auto &e: hashmap){
        num.push_back(e.first);
    }
    sort(num.begin(), num.end());
    for(auto e: num){
        count.push_back(hashmap[e]);
    }
    if(n>2*y || n<2*x){
        cout << result;
        return 0;
    }
    
    int sum = 0;
    
    for(int i=0; i<num.size(); ++i){
        sum += count[i];
        if(sum>=x && sum<=y){
            int sum2 = 0;
            int j = i+1;
            
            while(j < num.size()) sum2 += count[j++];
            if(sum2>=x && sum2<=y){
                result = num[i];
                break;
            }
        }
    }
        cout << result;
    
    return 0;
}
发表于 2023-03-11 11:46:43 回复(0)
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);
    }
}

发表于 2022-03-30 19:42:18 回复(0)
//麻烦各位大佬指点一下,为什么用例只通过了4/10?谢谢!

#include<iostream>
using namespace std;
int Q=10000;
int main()
{
    int m, n, x, y;
    int a[Q];
    cin >> n >> x >> y;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < n - i - 1; j++)
        {
            if (a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
    m = -1;
    for (int r = (x - 1); r <= (y - 1); r++)
    {
        if (2 * x > n || n + n % 2 > 2 * y)
    {
        break;
    }
        if (r <= (n - x - 1) && r >= (n - y - 1) && a[r] != a[r + 1])
        {
            m = a[r];
            break;
        }
    }
    cout << m << endl;
    return 0;
}
发表于 2022-03-15 17:14:26 回复(1)
#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;
}

发表于 2022-03-04 22:15:51 回复(0)
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[] scores = new int[n];
		for(int i = 0; i < n; i++){
			scores[i] = sc.nextInt();
		}
		Arrays.sort(scores);

		for(int i = 0; i< n; i++){
			int curScore = scores[i];
			if(scores[i+1] == curScore){
				i++;
			}

			int count = i + 1;
			int remain = n - count;
			if(count >= x && count <= y && remain >= x && remain <= y){
				System.out.println(curScore);
				return;
			}
		}

		System.out.println(-1);
	}
}

发表于 2021-10-24 16:15:35 回复(0)