1.淘汰分数
某比赛已经进入了淘汰赛阶段,已知共有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,否则输出符合条件的最小的值。
输入
6 2 3
1 2 3 4 5 6
输出
3
==思路:==简单理解题意,就是说给你一个区间[x,y],其实就是让总人数n通过一个数m分割开,使得m+(n-m)都在区间内,当然这个m需要是最小的m。
- 判断是否存在:当[x,y]中两次取最大值,这个最大值小于总人数n,那么不存在,或者两次取最小值,这个最小值大于总人数m,则不存在(这种情况在写的时候忘记了)
- 找出最小的m:这个题目最后演变为在[x,y]这个区间内选两个数i,j,使得i+j=n,同时i最小,那最简单的方法两次for循环即可。我使用的是第一次遍历i,当n-i在区间内时直接break,那么时间复杂度就为O(n)了,看题解可以使用二分查找的方式
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int length = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int[] score = new int[length];
for(int i = 0;i < length;i++){
score[i] = sc.nextInt();
}
int max = y + y;
if(max < length){ //这里少了一个判断条件
System.out.print(-1);
}else{
int i;
for(i = x;i <= y;i++){
if(x <= length - i && length - i <= y) break;
}
i--;
Arrays.sort(score);
System.out.print(score[i]);
}
}
}
2.正则序列
我们称一个长度为n的序列为正则序列,当且仅当该序列是一个由1~n组成的排列,即该序列由n个正整数组成,取值在[1,n]范围,且不存在重复的数,同时正则序列不要求排序
有一天小团得到了一个长度为n的任意序列,他需要在有限次操作内,将这个序列变成一个正则序列,每次操作他可以任选序列中的一个数字,并将该数字加一或者减一。
请问他最少用多少次操作可以把这个序列变成正则序列?
输入描述:
输入第一行仅包含一个正整数n,表示任意序列的长度。(1<=n<=20000)输入第二行包含n个整数,表示给出的序列,每个数的绝对值都小于10000。
输出描述:
输出仅包含一个整数,表示最少的操作数量。
输入
5
-1 2 3 10 100
输出
103
==思路:==主要是要明确改动最小方案的确定,如果输入序列是有序的,那么改动最好的方案就是输入序列中的i改动为正则序列中的i,这个可以通过数学归纳法进行证明
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int length = sc.nextInt();
int[] nums = new int[length];
for(int i = 0;i < length;i++){
nums[i] = sc.nextInt();
}
Arrays.sort(nums);
int res = 0;
for(int i =0; i < length;i++){
res += Math.abs((nums[i] - (i + 1)));
}
System.out.print(res);
}
}
3.公司食堂
小美和小团所在公司的食堂有N张餐桌,从左到右摆成一排,每张餐桌有2张餐椅供至多2人用餐,公司职员排队进入食堂用餐。小美发现职员用餐的一个规律并告诉小团:当男职员进入食堂时,他会优先选择已经坐有1人的餐桌用餐,只有当每张餐桌要么空着要么坐满2人时,他才会考虑空着的餐桌;
当女职员进入食堂时,她会优先选择未坐人的餐桌用餐,只有当每张餐桌都坐有至少1人时,她才会考虑已经坐有1人的餐桌;
无论男女,当有多张餐桌供职员选择时,他会选择最靠左的餐桌用餐。现在食堂内已有若干人在用餐,另外M个人正排队进入食堂,小团会根据小美告诉他的规律预测排队的每个人分别会坐哪张餐桌。
输入描述:
第一行输入一个整数T(1<=T<=10),表示数据组数。每组数据占四行,第一行输入一个整数N(1<=N<=500000);第二行输入一个长度为N且仅包含数字0、1、2的字符串,第i个数字表示左起第i张餐桌已坐有的用餐人数;第三行输入一个整数M(1<=M<=2N且保证排队的每个人进入食堂时都有可供选择的餐桌);第四行输入一个长度为M且仅包含字母M、F的字符串,若第i个字母为M,则排在第i的人为男性,否则其为女性
输出描述:
每组数据输出占M行,第i行输出一个整数j(1<=j<=N),表示排在第i的人将选择左起第j张餐桌用餐。
输入
1
5
01102
6
MFMMFF
输出
2
1
1
3
4
4
==思路:==最简单的思路,直接超时。遍历性别数组,然后遍历table数组,时间复杂度是O(n2),不出意外是会超时的。看题解的思路:使用优先队列,分别建立三个优先队列,存放人数为0,1,2的桌子,因为使用的是优先队列,所以每次出队的时候都是选择当前最小元素,那么就对应着从左到右选择
对于M来说,有以下情况:
- 人数为1的优先队列不为空,则该桌子下标弹出队,加入到人数为2的队列里
- 人数为1的优先队列为空,则选择人数为0的桌子下标出队,加入到人数为1的队列里
对于F来说,情况一样,此题还需要注意的是不能使用Scanner做输入输出,这样会超时
优先队列:每次出队的是都是当前队里最小(最大)的元素,因为内部使用的是堆实现,所以出队的时间复杂度为O(logn)
//我的错误思路
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
int count = Integer.parseInt(reader.readLine());
while(--count >= 0){
int length = Integer.parseInt(reader.readLine());
String s = reader.readLine();
char[] r = s.toCharArray();
int[] co = new int[r.length];
for(int i = 0;i < r.length;i++){
co[i] = Integer.valueOf(r[i]) - 48;
}
int nums = Integer.parseInt(reader.readLine());
String sex = reader.readLine();
char[] csex = sex.toCharArray();
int[] res = new int[csex.length];
for(int j = 0;j < csex.length;j++){
if(csex[j] == 'M'){
int flag = 0;
int flag2 = 0;
int empty = 0;
for(int i = 0; i < co.length;i++){
if(flag2 == 0 && co[i] == 0){
empty = i;
flag2 = 1;
}
if(co[i] == 1){
co[i]++;
res[j] = i;
flag = 1;
break;
}
}
if(flag == 0){
res[j] = empty;
co[empty]++;
}
}else{
int flag = 0;
int flag2 = 0;
int empty = 0;
for(int i = 0;i < co.length;i++){
if(co[i] == 0){
co[i]++;
res[j] = i;
flag = 1;
break;
}
if(flag2 == 0 && co[i] == 1){
empty = i;
flag2 = 1;
}
}
if(flag == 0){
res[j] = empty;
co[empty]++;
}
}
}
for(int i = 0;i < res.length;i++){
writer.write(Integer.toString(res[i] + 1));
writer.newLine();
}
writer.flush();
}
}
}
使用优先队列的题解
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
int count = Integer.parseInt(reader.readLine());
while(--count >= 0){
int tableLength = Integer.parseInt(reader.readLine());
String table = reader.readLine();
int[] tables = new int[tableLength];
for(int i = 0;i < tableLength;i++){
tables[i] = table.charAt(i) - '0';
}
int peopleLength = Integer.parseInt(reader.readLine());
String people = reader.readLine();
List<PriorityQueue<Integer>> pqs = new ArrayList<>();
pqs.add(new PriorityQueue<Integer>());
pqs.add(new PriorityQueue<Integer>());
pqs.add(new PriorityQueue<Integer>());
for(int i = 0;i < tableLength;i++){
pqs.get(tables[i]).add(i);
}
int[] res = new int[peopleLength];
for(int i = 0;i < peopleLength;i++){
int index;
if(people.charAt(i) == 'M'){
if(!pqs.get(1).isEmpty()){
index = pqs.get(1).poll();
pqs.get(2).add(index);
res[i] = index;
}else{
index = pqs.get(0).poll();
pqs.get(1).add(index);
res[i] = index;
}
}else{
if(!pqs.get(0).isEmpty()){
index = pqs.get(0).poll();
pqs.get(1).add(index);
res[i] = index;
}else{
index = pqs.get(1).poll();
pqs.get(2).add(index);
res[i] = index;
}
}
}
for(int j = 0;j < peopleLength;j++){
writer.write(Integer.toString(res[j] + 1));
writer.newLine();
}
writer.flush();
}
}
}