C언어로 백준 풀기 | 팩토리얼, 팩토리얼 0의 개수 (재귀 함수 써? 말아?)

설탕·2024년 3월 20일

문제 10872. 팩토리얼

재귀호출 함수의 대표적 예시인 팩토리얼 구하는 함수로 풀었다.
탈출 조건이 필수로 있어야 한다. 그렇지 않으면 무한으로 호출하다가 스택 오버플로우가 발생한다.

#include <stdio.h>

int factorial(int num);

int main(void)
{
  int num;
  scanf("%d", &num);

  printf("%d\n", factorial(num));

  return 0;
}

int factorial(int num)
{
  if (num <= 1) return 1;
  return num * factorial(num - 1);
}

이전 글에서 작성했듯이 main 함수 위에 factorial 함수를 선언하고, main 함수 안에서 다른 함수를 정의할 수 없기 때문에 main 함수 아래에 factorial 함수를 정의했다.

문제 1676번. 팩토리얼 0의 개수

처음에는 이 문제도 똑같이 팩토리얼을 재귀 함수로 구하고, 그 다음 0의 개수를 세는 방식으로 풀었다. 그러나...

시간 초과로 바로 컷 당하고... 다시 읽어보니 이 문제에서는 N이 최대 500이었다. 500!long long으로도 담을 수 없는 무지막지한 숫자이다. 팩토리얼을 직접 구해서 풀지 말라는 뜻이다.

그럼 어떻게 해야 할까?
2와 5를 곱하면 끝 자리에 0이 생긴다. 즉 N!을 소인수분해했을 때 인수 2의 개수와 인수 5의 개수 중 더 작은 수가 0의 개수가 된다. 그런데 1부터 N까지의 자연수 중에서는 2의 배수 개수가 5의 배수 개수보다 같거나 더 많을 수밖에 없기 때문에 어차피 인수 5의 개수만 세면 된다.

#include <stdio.h>

int main(void)
{
  int num, count = 0;
  scanf("%d", &num);

  for (int i = 1; i <= num; i++) // 1부터 N까지 반복
  {
    if (i % 5 == 0) {
      int divisor = i;      
      do
      {
        count++;
        divisor /= 5;
      } while (divisor % 5 == 0 && divisor / 5 >= 1);
    }
  }
  
  printf("%d\n", count);
  
  return 0;
}

1부터 N까지 반복문을 한 번 돌면서, i가 5의 배수이면 count를 센다.
그런데 25, 125 같은 경우에는 인수 5를 한 개만 갖고 있는 게 아니라 2개, 3개씩 갖고 있다. 그럴 경우 count도 2, 3씩 세어주어야 한다. i를 반복문 내부에서 변경하면 안 되므로 다른 변수(divisor)에 복사해주고, 5로 나누어떨어지는 자연수인 동안은 계속 5로 나누면서 count를 세는 것을 반복한다. 예를 들면 divisor가 125일 때 125 → 25 → 5까지 계속 count를 세고 1이 되면 do ~ while문을 탈출한다.

성공!

profile
공부 기록

0개의 댓글