백준 11401 이항 계수 3

2020. 9. 13. 18:39·알고리즘/BOJ

www.acmicpc.net/problem/11401

 

11401번: 이항 계수 3

자연수 \(N\)과 정수 \(K\)가 주어졌을 때 이항 계수 \(\binom{N}{K}\)를 1,000,000,007로 나눈 나머지를 구하는 프로그램을 작성하시오.

www.acmicpc.net

머리가 아파오는 수학 문제다.

이 문제는 해답을 참고해서 풀었다.

기본적으로 

  • 페르마의 소정리를 이용
  • 확장 유클리드 호제법을 이용

이외에 소인수 분해로 푸는 방법이 있는 것 같은데, 나는 페르마의 소정리를 이용해서 풀었다.

 

페르마의 소정리는 소수 p와 정수 a에 대해 다음을 만족한다.

 

$$a^{(p-1)}\equiv1\;(mod\;p)$$

 

따라서 $$nCk = \frac{k!}{(n-k)!}$$

 

에서 n! = A, k!(n-k)! = B로 치환한다.

 

우리가 구해야 할 것은 $$AB^{-1}\; \% \;P$$ 인데

 

기본적으로 모듈러 연산은 더하기, 빼기, 곱하기 까진 성립 하지만 나머지에 대해선 성립하지 않는다.

그래서 페르마의 소정리를 이용하여 분수 꼴에서 정수 꼴로 바꾸어 계산한다.

 

 

$$B^{p-1} \; = \;1\;(mod\;P)$$ 이므로

$$B\;*\;B^{p-2}\;=\;1\;(mod\;P)$$ 이고

$$B^{p-2}\;=\;B^{-1}\;(mod\;P)$$ 

$$B^{-1}\;=\;B^{p-2}\;\%\;P$$ 이다

 따라서 

$$(A\%P)(B^{p-2}\%P)\%P $$

임을 알 수 있다.

 

치환했던 것을 풀어보면

$$(N!\%P)((N!(N-K)!^{P-2}\%P))\%P$$

이다.

 

여기까지 구했다면 나머지는 쉽다.

#include <cstdio>
using namespace std;
using ll = long long;
#define MOD 1000000007LL

ll fac[4000001];

void factorial() {
	fac[0] = fac[1] = 1;
	for (int i = 2; i < 4000001; i++) {
		fac[i] = (fac[i - 1] * i) % MOD;
	}
}

ll power(ll a, ll b) {
	if (b == 0) return 1;
	if (b % 2 > 0) return (power(a, b - 1) * a) % MOD;
	ll half = power(a, b / 2) % MOD;
	return half * half % MOD;
}

int main() {
	int n, k;
	scanf("%d%d", &n, &k);
	if (n == k || k == 0) {
		printf("1"); return 0;
	}
	factorial(); //팩토리얼 한번에 구해놓기
	
	//페르마의 소정리로 { (n!%MOD) * (k!*(n-k)!)^MOD-2 % MOD } % MOD

	ll A = fac[n] % MOD; 
	ll B = (power(fac[k], MOD - 2) % MOD * power(fac[n - k], MOD - 2) % MOD);
	printf("%lld", (A * B) % MOD);

	return 0;
}

주의해야 할 점은 

	ll B = (power(fac[k], MOD - 2) % MOD * power(fac[n - k], MOD - 2) % MOD);

이 식에서 각각의 fac[k]*fac[n-k]의 식으로 해주면 오버플로가 발생하는 것 같다.

그래서 따로 처리해줬더니 맞았다.

 

 

'알고리즘 > BOJ' 카테고리의 다른 글

BOJ 2343 기타 레슨  (0) 2020.09.15
BOJ 2512 예산  (0) 2020.09.14
백준 10816 숫자 카드 2  (0) 2020.09.11
백준 1655 가운데를 말해요  (0) 2020.09.11
백준 1167 트리의 지름  (0) 2020.09.10
'알고리즘/BOJ' 카테고리의 다른 글
  • BOJ 2343 기타 레슨
  • BOJ 2512 예산
  • 백준 10816 숫자 카드 2
  • 백준 1655 가운데를 말해요
khyu2
khyu2
  • khyu2
    dev log
    khyu2
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 알고리즘
        • BOJ
        • Programmers
        • Algorithm
        • SWEA
      • 개발
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    완전 탐색
    분할 정복
    우선순위 큐
    이분 탐색
    소수
    트리
    BFS
    행렬 제곱
    이분탐색
    시뮬레이션
    구현
    완전탐색
    dfs
    알고리즘
    팰린드롬
    코딩테스트 연습
    SWEA
    GREEDY
    유니온 파인드
    프로그래머스
    BOJ
    MST
    다익스트라
    큐
    dp
    조합
    크루스칼
    냅색
    피보나치 수
    피사노 주기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
khyu2
백준 11401 이항 계수 3
상단으로

티스토리툴바