ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 2004번: 조합 0의 개수
    코딩(Coding)/백준 문제풀이 2021. 1. 11. 10:56
    728x90

    링크: www.acmicpc.net/problem/2004

     

    2004번: 조합 0의 개수

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

    www.acmicpc.net

     

    조합 0의 개수

    문제

    nCm의 끝자리 0의 개수를 출력하는 프로그램을 작성하시오.

    입력

    첫째 줄에 정수 n, m (0≤m≤n≤2,000,000,000, n≠0)이 들어온다.

    출력

    첫째 줄에 nCm의 끝자리 0의 개수를 출력한다.


    문제접근

    이번 문제는 수학문제이면서 약간의 논리가 필요한거 같다. 우선 조합 nCr의 일반식을 입력해보면

    nCr = n!/((n-r)! * r!)이다.

    처음에 나는 위 공식을 이용해서 값을 구한다음 뒤에서 부터 0의 개수를 세는 방식으로 문제를 접근했다.

    그러나 역시 다른 뜻이 있었다는 걸 보여주듯이 시간 초과가 나타났다.

     

    더보기
    import sys
    
    def facto(n):
        if n == 0 or n == 1:
            return 1
        else:
            result = 1
            for i in range(1,n+1):
                result *= i
            return result
    
    def comb(n, m):
        return int(facto(n)/(facto(n-m) * facto(m)))
    
    def calc(n, m):
        data = comb(n,m)
        data = reversed(str(data))
        count = 0
        for i in data:
            if(i == '0'):
                count += 1
            else:
                break;
        return count
    
    def main():
        n, m = sys.stdin.readline().split()
        n = int(n); m = int(m)
        print(calc(n,m))
    
    if __name__ == "__main__":
        main()

     

    숫자가 20억까지면 int형의 거의 끝 숫자까지 사용한다는 것인데, 당연히 시간초과가 날 것을 간과했다... ㅍ_ㅍ;;;

     

    따라서 단순히 공식으로 풀어내는 것이 아니라 다른 방법을 통해 문제를 푸는 것인데, 자연수에서 "1000"은 10이 3번 곱해진 것이다. 또 "4300"은 43에 10이 2번 곱해진 것이다. 따라서 입력으로 주어진 수(nCm)의 10의 개수를 세면 뒤에 존재하는 0의 개수를 얻을 수 있다.

     

    그러나 nCm은 수가 커지면 시간초과가 나온다. 따라서 nCm의 공식에서 분자와 분모를 나누어서 10의개수를 세고 분자의 10의 개수에서 분모의 10개수를 빼면(뺀다고 표현했지만 사실 약분을 하는 것이다.) nCm의 10의 개수를 얻을 수 있다.

     

    여기서 10은 2와 5로 나뉜다. 따라서 입력으로 주어진 수의 분자와 분모 2와 5의 개수를 세어서 빼준 후(약분), 2와 5 개수의 최소값을 통해 0의 개수를 얻을 수 있다는 결론이 나온다.


    코드

    """
    백준 알고리즘 2004번: 조합 0의 개수
    https://www.acmicpc.net/problem/2004
    
    nCr = n!/((n-r)! * r!)
    아 시간초과...
    0의 개수는 10이 생겨날때마다 늘어난다.
    10 = 2 * 5로만들어짐 따라서
    분자 n의 5의 개수에서 m, n-m의 5의 개수를 빼고(약분 하는 거임)
    분자 n의 2의 개수에서 m, n-m의 2의 개수를 뺀다(약분)
    2는 100개 있는데 5가 1개있으면 10은 1개 만들어 지므로
    둘중에 제일 작은 수를 구하면 그게 답 
    """
    import sys
    
    def count2(n):
        count = 0
        while n != 0:
            n = n//2
            count += n
        return count
    
    def count5(n):
        count = 0
        while n != 0:
            n = n//5
            count += n
        return count
    
    def calc(n, m):
        cnt2 = count2(n) - (count2(m) + count2(n - m))
        cnt5 = count5(n) - (count5(m) + count5(n-m))
        return min(cnt2, cnt5)
    
    def main():
        n, m = sys.stdin.readline().split()
        n = int(n); m = int(m)
        print(calc(n,m))
    
    if __name__ == "__main__":
        main()
    728x90

    댓글

Designed by black7375.