2004번: 조합 0의 개수

첫째 줄에 정수 $n$, $m$ ($0 \le m \le n \le 2,000,000,000$, $n \ne 0$)이 들어온다.

www.acmicpc.net

문제 분석

  • 제한 시간 2초 : Big-O기준 약 2억 연산
  • 입력되는 정수 최댓값 : 20억
  • 수행시간 O(n) 불가, 최대한 연산을 줄여야 한다.
  • 20억의 수가 들어올 수 있으므로 변수의 메모리를 넉넉하게 long long 으로 할당한다.
  • nCr : n!/(r!(m-r)!)
  • 뒷 자리에 0이 생기려면 10이 곱해져야 한다.(10 = 2 x 5)

풀이 방식

  • n부터 n보다 작은 수 중에 2ⁱ 의 배수의 개수를 센다.( i 는 1부터 2ⁱ ≤ n) --- f2(n)
  • n부터 n보다 작은 수 중에 5ⁱ 의 배수의 개수를 센다.( i 는 1부터 5 ≤ n) --- f5(n)
  • m, n-m 도 똑같이 진행해준다.
  • f2(n) - (f2(m) + f2(n-m)) 와 f5(n) - (f5(m) + f5(n-m)) 를 비교해 더 작은 값을 출력한다.

f2(x), f5(x) 구하기

  • x부터 x보다 작은 모든 수에 대해 하나하나 배수의 개수를 세는 방식은 시간초과가 날 것이 뻔하다.
  • f2(x)를 구할 때, 먼저 2의 배수의 개수를 구해준다. -> ⎣x/2⎦
    그리고 i를 증가 시키며 2ⁱ의 배수의 개수를 구한다.
    2ⁱ의 배수의 개수를 더해간다.
  • 원리 :
    1. 1부터 어떤 수 A 까지 2의 배수(짝수)의 개수를 구하는 법 -> ⎣A/2⎦
    2. 1단계에서 소인수로 2를 하나이상 갖는 수는 셋다.
    3. 2를 소인수로 두개이상 갖는 수는 2² (= 4) 로 나눠주어 세면 된다.
    4. 위와 같은 방식으로 2ⁱ 배수의 개수를 더해가며 f2(n)을 구한다.
  • f5(x)도 같은 방식으로 구한다.
#include <iostream>

using namespace std;

long long int n, m, result;

long long int fTwo(long long int x) {
    long long int cnt = 0;
    for (long long int i = 2; i <= x; i *= 2) { // 2ˣ의 배수의 개수를 센다
        cnt += x / i;
    }
    return cnt;
}

long long int fFive(long long int x) {
    long long int cnt = 0;
    for (long long int i = 5; i <= x; i *= 5) { // 5ˣ의 배수의 개수를 센다
        cnt += x / i;
    }
    return cnt;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    fTwo(n) - fTwo(m) - fTwo(n - m) < fFive(n) - fFive(m) - fFive(n - m) ?
            result = fTwo(n) - fTwo(m) - fTwo(n - m) :
            result = fFive(n) - fFive(m) - fFive(n - m);

    cout << result << "\n";
    return 0;
}

느낀점

  • x부터 x보다 작은 모든 수에 대해 하나하나 배수의 개수를 세는 방식으로 풀었다. 당연히 값은 제대로 나오지만 시간초과가 떴다.
  • 2ⁱ의 배수의 갯수를 세는 방법을 구현 하며 2의 배수의 갯수부터 세보다가 짝수의 갯수를 세고 있다는 생각이 들었다.
  • 처음엔 한 수에 2는 몇개고 4는 몇개고 2ⁱ는 몇갠지 셌었는데 짝수의 갯수를 세는 방법을 떠올리고는 문제를 빠르게 풀어냈다.
  • 처음에 IDE 부터 켜서 풀다가 고민을 오래해보고 푸니 금방 풀었다. ( 제발 고민좀 오래하고, 시간복잡도 계산 해보고 풀자!!!!)

시간 복잡도

  • result 구하기 : O(1)
  • f2 : O(log₂n) -> O(logn)
  • f5 : O(log₅n) -> O(logn)
    ➣O(logn)

 

'Algorithm > baekjoon' 카테고리의 다른 글

[BOJ 6603] 로또  (0) 2022.07.31
[BOJ 3036] 링  (0) 2022.07.31
[BOJ 9020]골드바흐의 추측  (0) 2022.07.31
[BOJ 4948]베르트랑 공준  (0) 2022.07.30
[BOJ 1655] 가운데를 말해요  (0) 2022.07.30

+ Recent posts