某比赛已经进入了淘汰赛阶段,已知共有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; }
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); } }