문제
리뷰
문제를 풀기 전에, 팩토리얼 0의 개수 문제를 다시 풀고 왔다.
아래는 조합을 구하는 식이다. 조합은 팩토리얼의 나눗셈과 곱셈으로 이루어져 있다.
그래서 이 문제는 n! 과 r! 과 (n-r)! 을 각각 계산해야 한다.
nCm의 끝자리 0의 개수는 10이 얼마나 곱해졌는지가 좌우한다.
10은 2x5 다.
그래서 n! 과 r! 과 (n-r)! 이렇게 3개의 팩토리얼에 2와 5가 몇 번 곱해져있는지 계산해야 한다.
five_cnt 함수는 5의 개수를 리턴한다. two_cnt 함수도 똑같은 구조다.
int five_cnt(int n){ // 5의 개수 구한다
int cnt = 0;
for(long long i = 5; 1 <= (n/i); i *= 5){
cnt += (n/i);
}
return cnt;
}
n과 m은 최대 2,000,000,000 의 숫자가 주어진다.
5를 곱해가면서 n을 나눌꺼니까 int의 표현범위를 넘을 것을 감안하여 long long 으로 선언한다.
two_cnt 함수는 2의 개수를 리턴한다.
two_cnt와 five_cnt 함수로 2와 5의 개수를 구하되, 둘 중에 작게 나온 값이 인수 10의 개수가 될 것이다.
n C r 조합에서 유의할 점 2가지
r == 0이면, 항상 1이다. 아무것도 안고르기 때문이다. n개중에 0개.
n == r 이면, 항상 1이다. 전부 고르기 때문이다. n개중에 n개.
따라서 n C m 이 주어졌을 때, m이 1인 경우, 2와 5의 숫자를 안구해도 된다. 어차피 1이기 때문이다.
n==m 인 경우에도 1이니까 2와 5의 숫자를 안구해도 된다.
// 5, 2의 개수를 각각 구해서 작은 쪽을 출력한다
five += five_cnt(n);
if(m > 0) five -= five_cnt(m);
if(n != m) five -= five_cnt(n-m);
맞은 코드
#include <iostream>
#include <algorithm>
using namespace std;
int n, m;
int two, five;
int two_cnt(int n){ // 2의 개수 구한다
int cnt = 0;
for(long long i = 2; 1 <= (n/i); i *= 2){
cnt += (n/i);
}
return cnt;
}
int five_cnt(int n){ // 5의 개수 구한다
int cnt = 0;
for(long long i = 5; 1 <= (n/i); i *= 5){
cnt += (n/i);
}
return cnt;
}
int main(void){
cin >> n >> m;
// 5, 2의 개수를 각각 구해서 작은 쪽을 출력한다
five += five_cnt(n);
if(m > 0) five -= five_cnt(m);
if(n != m) five -= five_cnt(n-m);
two += two_cnt(n);
if(m > 0) two -= two_cnt(m);
if(n != m) two -= two_cnt(n-m);
cout << min(two, five);
return 0;
}
728x90
'알고리즘 > 백준' 카테고리의 다른 글
진법변환2 백준 11005번 c++ (0) | 2020.09.15 |
---|---|
GCD합 백준 9613번 (0) | 2020.09.15 |
소인수분해 백준 11653번 (0) | 2020.09.14 |
골드바흐의 추측 백준 6588번 (0) | 2020.09.14 |
소수 구하기 백준 1929번 에라토스테네스의 체 (0) | 2020.09.14 |