물론 다들 아시겠지만, 해당 문제는 간단한 공식으로 푸는 문제입니다.
예를 들어 30개의 공에서 5개를 꺼내는 경우 아래와 같은 수식으로 풀 수 있습니다.
30 * 29 * 28 * 27 * 26 / 1 * 2 * 3 * 4 * 5
물론 위와 같이 방식으로 해결을 하려고 하면 오버플로우가 발생하게 됩니다. 파이썬으로 검산해 본 결과
30! 의 경우 값이 265,252,859,812,191,058,636,308,480,000,000 이 나오기 때문에,
다른 언어들의 경우 단순히 Long 타입으로 사용한다고 해도 해결이 안됩니다.
따라서 한번에 곱한 후 나누는 것이 아니라 아래와 같이 단계별로 계산하는 방법을 사용해야 합니다.
(30 / 1) * (29 / 2) * (28 / 3) * (27 / 4) * (26 / 5)
다만 위와 같은 방식으로 해결하려고 하면 이번에는 28/3 의 경우 무한 소수이기 때문에 부동소수점 문제가 발생합니다.
수식도 정확하고 오버플로우도 발생하지 않지만, 결국 최종 정답을 구했을 때 부동소수점 오차로 인해 정답이 틀리는 케이스가 발생하게 됩니다.
그래서 먼저 나눈 값을 기존 값에 곱하는 것이 아니라, 아래와 같이 기존 계산된 값에 분자를 먼저 곱한 후 분모를 나눠주는 방법으로 접근해야 합니다.
n개의 연속된 정수에는 항상 n의 배수가 포함되기 때문에 항상 정수 값이 나와서 부동소수점 문제를 피할 수 있습니다.
(((((30 / 1) * 29 / 2) * 28 / 3) * 27 / 4) * 26 / 5)
파이썬으로 모든 케이스에 대한 정답을 구해 본 결과 최대 값은 (30, 15)인 경우 155,117,520 으로 Int 범위 안에 있지만 위와 같은 방법으로 계산을 했을 때 30C14에서 15를 곱하는 순간 Int 형은 오버플로우가 발생합니다.
따라서 코틀린 같은 경우 람다식으로 간단히 계산 가능하지만, 이 경우 계산 후 Long을 씌우는 것이 아니라 수식안의 모든 변수들에 .toLong() 을 붙여서 Long Type으로 계산을 해야만 오버플로우를 피할 수 있습니다.
감사합니다!
감사합니다!
감사합니다! 이해가 잘되네요
계산식에서 나누기하나를 잘못 쓰신것 같은데, 아닌가요? 27 앞에 나누기를 잘못 쓰신 것 같아요. 이렇게 해야 하는거 같아요. (((((30 / 1) * 29 / 2) * 28 / 3) * 27 / 4) * 26 / 5)
아 그러네요 틀린 데 없는 지 몇 번을 보고 올려도 나중에 보면 항상 오타가ㅠ 감사합니다 수정했습니다.
감사합니다. 그랬겠네요.
감사합니다. 3번 힌트 덕분에 해결하였습니다. 코딩 외에 수학적인 머리도 써야했네요...
와우! 감사합니다
진짜 너무 감사합니다!! 채점 4번까지만 통과하고 계속 실패했었는데... 덕분에 통과했습니다!