자료구조/문제풀이

[백준 JAVA] 2004 조합 0의 개수

휴먼코딩 2024. 7. 6. 17:39

이항계수 다 까먹었는데............

부랴부랴 개념정립을 위해 확통 인강 듣고 풀었다.

역시 뭐든 기초개념이 가장 중요하다.....

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main_2004이항계수 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        // 끝자리 0은 10의 배수에서 오는 것으로, 소인수분해한 2와 5의 배수의 조합에 의해 정해진다.
        // 따라서 끝자리 0의 개수를 구하기 위해서는 n! 에서 2의 배수와 5의 배수의 개수를 구한뒤
        // m! 과 (n-m)! 에서의 2의 배수와 5의 배수를 빼준다.

        // 끝자리 0의 개수를 구하기 위해서는 2와 5의 배수의 개수를 따로 계산하고
        //그 중 작은 값을 끝자리 0의 개수로 결정한다.
        long count2 = countFactors(n, 2) - countFactors(m, 2) - countFactors(n - m, 2);
        long count5 = countFactors(n, 5) - countFactors(m, 5) - countFactors(n - m, 5);

        //5와 2의 승수 중에서 작은 값이 0의 끝자리이다.
        //0 (10의 배수) = (2x5)
        System.out.println(Math.min(count2, count5));
    }

    // n!에서 num의 배수의 개수를 구하는 함수
    private static long countFactors(int n, int num) {
        long count = 0;      // 배수의 개수를 저장할 변수
        long factor = num;   // 배수를 나타내는 변수, 초기값은 num

        // factor가 n 이하일 때까지 반복
        while (factor <= n) {
            count += n / factor;  // n을 factor로 나눈 몫을 count에 더한다
            if (factor > Long.MAX_VALUE / num) break;  // 오버플로우 방지를 위한 조건 
                                                          (오버플로우 = 값 초과)
            factor *= num;  // factor에 num을 곱해 다음 배수를 계산
        }

        return count;  // 계산된 배수의 개수 반환
    }
}

 

 

처음에 int 형 쓰다가 팩토리얼 쓸때도 int를 사용해서... 오버플로우 문제로 런타임 오류가 떴고

long을 써도 초과할 수가 있어서 초과할시 멈추도록 조건을 걸어줬다...

 

여러모로 개념이 가장 중요했던 문제

 

시간복잡도

factor가 n을 초과할 때 까지 루프를 실행하고 = 팩토리얼

문제에선 2와 5의 승수를 구해야 되기(10의 소인수) 때문에

시간 복잡도는 O(log_2(n) + log_5(n)) 이다.