소프티어 성적 평가 자바

꾸준하게 달리기~·2023년 9월 12일
0
post-thumbnail

문제는 다음과 같다.
https://softeer.ai/practice/result.do?eventIdx=1&submissionSn=SW_PRBL_SBMS_257643&psProblemId=1309

문제
현주는 N명의 인원이 참여하는 프로그래밍 스터디 그룹을 이끌고 있다.

현주는 스터디를 위해 대회를 세 개 개최하였고, 모든 구성원이 각 대회에 참여하였다. 
참가자는 각 대회에서 0 이상 1,000 이하의 정수인 점수를 얻는다. 
한 대회에서 둘 이상의 참가자가 동점이 나오는 경우도 있을 수 있다.

현주는 각 대회별 등수 및 최종 등수를 매기고 싶다. 
등수는 가장 점수가 높은 사람부터 1등, 2등, ···, N등의 순서대로 붙는다. 
만일 동점이 있을 경우 가능한 높은 (등수의 수가 작은) 등수를 부여한다. 
즉, 점수가 내림차순으로 10,7,6,6,4의 순서일 경우, 
6점을 받은 두 사람은 공동 3등이 되고, 그 다음 순서인 4점을 받은 사람은 5등이 된다.
이 규칙을 다르게 표현하면 다음과 같다: 
각 사람마다 “나보다 점수가 큰 사람”의 수를 세어 1을 더한 것이 자신의 등수가 된다. 
대회별 등수는 각 대회에서 얻은 점수를 기준으로 하며 최종 등수는 
세 대회의 점수의 합을 기준으로 한다.


각 참가자의 대회별 등수 및 최종 등수를 출력하는 프로그램을 작성하시오.

제약조건
3 ≤ N ≤ 100,000

입력형식
첫째 줄에 참가자의 수를 나타내는 정수 N이 주어진다.
이어 세 개의 줄에 각 대회의 결과를 나타내는 N개의 정수가 주어진다. 
이중 i번째 정수는 그 대회에서 i번째 사람이 얻은 점수를 의미한다.

출력형식
첫 세 개의 줄에는 각 참가자의 대회별 등수를 출력한다. 
즉 이중 c번째 줄의 i번째 정수는 c번째 대회에서의 i번째 사람의 등수를 의미한다.
이어 새로운 줄에 같은 형식으로 각 참가자의 최종 등수를 출력한다.


입력예제1
3
40 80 70
50 10 20
100 70 30

출력예제1
3 1 2
1 3 2
1 2 3
1 2 3


입력예제2
3
1000 1000 700
300 100 400
200 400 400

출력예제2
1 1 3
2 3 1
3 1 1
1 1 1





풀이는 다음과 같다.

import java.util.*;
import java.io.*;


public class Main {
    public static void main(String args[]) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int N = Integer.parseInt(br.readLine());

        int[] arr1 = new int[N];
        int[] arr2 = new int[N];
        int[] arr3 = new int[N];
        int[] arr4 = new int[N];


        for(int c = 0 ; c < 3 ; c++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            
            for(int i = 0 ; i < N ; i++) {
                int a = Integer.parseInt(st.nextToken());
                arr1[i] = a;
                arr2[i] += a;
                arr3[i] = a;
                arr4[i] += a;
            }

            Arrays.sort(arr1);

            for(int i = 0 ; i < N ; i++) {
                bw.write(String.valueOf(N+1-bs(arr1, arr3[i])) + " ");
            }
            bw.write("\n");
        }

        Arrays.sort(arr2);

        for(int i = 0 ; i < N ; i++) {
            bw.write(String.valueOf(N+1-bs(arr2, arr4[i])) + " ");
        }

        bw.flush();
        bw.close();
    }

    static int bs(int[] arr, int want) { //나보다점수높+1 -> 어퍼바운드+1
        int s = 0;
        int e = arr.length;

        while(s < e) {
            int m = (s+e)/2;

            if(arr[m] > want) e = m;
            else s = m+1;
        }
        return s;
    }
}

3번의 시험 점수가 주어진다.
해당 점수를 통해 등수를 매기면 된다.
여기서 떠오르는 생각 -> 점수 순으로 줄세우고, 등수 매기기?
맞다. 이분탐색이다.

문제에서 주어진 조건대로
내 등수 : 나보다 점수 높은사람의 수 + 1
이므로,
upper bound를 탐색하면 된다.

주의할점은,
점수를 오름차순 해줬기 때문에, 높은 점수일 수록 뒤로 간다.

ex
10 20 30 40 50

그렇다면, 50점이 1등이어야 하지만 index는 4 이므로,
해당 부분을 주의해서 등수를 매겨주면된다.
해당 부분에 대한 코드는 아래와 같다.

String.valueOf(N+1-bs(arr2, arr4[i]))

->    N+1 - (upper bound의 index)
profile
반갑습니다~! 좋은하루 보내세요 :)

2개의 댓글

comment-user-thumbnail
2023년 9월 16일

왜 요새는 글 안 올리시죠? 혹시 제주도라도 가신건가요?

1개의 답글