코딩테스트/백준

P.27172 수 나누기 게임

박 성 하 2023. 8. 15. 16:50
728x90

코드

package Baekjoon.Class;

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

public class P_27172 {

    static int max = 0;
    static int n;
    static int[] arr;
    static boolean[] nums = new boolean[1000001];
    static int[] score;

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

        n = Integer.parseInt(br.readLine());
        arr = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        for (int i = 0; i < n; i++) {
            max = Math.max(max, arr[i]);
            nums[arr[i]] = true;
        }

        score = new int[max + 1];
        sieve();

        for (int i : arr) {
            bw.write(score[i] + " ");
        }

        bw.flush();

        bw.close();
        br.close();
    }

    private static void sieve() {
        for (int i = 0; i < n; i++) {
            for (int j = 2 * arr[i]; j <= max; j += arr[i]) {
                if (nums[j]) {
                    score[j]--;
                    score[arr[i]]++;
                }
            }
        }
    }
}

코드 설명

에라토스테네스의 체를 응용하는 방법으로 해결했다.일반적인 에라토스테네스의 체는 다음과 같다.

boolean[] sieve = new boolean[max + 1];
    Arrays.fill(sieve, true);
    for (int i = 2; i * i <= max; i++) {
        if (sieve[i]) {
            for (int j = i; j <= max; j += i) sieve[j] = false;
        }
    }
}

소수와 합성수를 판별하는 알고리즘인데 약수를 찾는 코드로 바꾸어 봤다.

달라진 점은 i가 입력 받은 배열의 원소만 참조한다는 것이다.

브루트포스 + 에라토스테네스의 체로 보면 이해가 쉬울 것 같다.

 

문제는 시간이었다.

처음에는 약수를 ArrayList에 저장하여 main에서 이 약수가 입력받은 arr에 존재하는지 확인하는 작업을 했다.

이 때 다시 약수 리스트 혹은 입력 받은 리스트를 순회해야하므로 sieve() 함수에서 약수를 구하려고 브루트포스를 한 것이 의미가 없는 행동이 되어버린다.

 

따라서 score 계산을 sieve()함수에서 곧바로 해주는 방식을 택했다.

이 방식의 경우 대상 넘버(j)와 약수(i)가 arr에 존재하는지 확인을 해주는 작업이 필요하다. 

무턱대고 score를 변경해버리면 입력 받은 배열 내에서의 score가 아닌 1부터 MAX까지의 배열에서의 score가 구해지게 된다.

이 작업은 결국 입력 받은 배열의 순회를 초래하는데 이럴 경우 n * MAX / 2 * n이 되면서 시간초과가 발생한다.

이를 해결하기 위해 문제에서 주어진 최대 정수 크기인 1,000,000를 포용할 수 있는 boolean 배열을 두고 입력받은 배열의 원소의 경우 true로 바꾸어 sieve() 함수에서 O(1) 참조가 가능하게 해 주었다.

 

728x90

'코딩테스트 > 백준' 카테고리의 다른 글

P.1647 도시 분할 계획  (0) 2023.08.17
P.1197 최소 스패닝 트리  (0) 2023.08.17
P.2467 용액  (0) 2023.08.15
P.2166 다각형의 면적  (0) 2023.08.14
P.11779 최소비용 구하기 2  (0) 2023.08.13