출처: 백준 알고리즘
주소: www.acmicpc.net/problem/11401

문제요약:
-> 이항계수 (N, K)을 1,000,000,007으로 나눈 나머지에 대해 출력
해결방법:
1) 이항계수 (N, K)을 구해서 1,000,000,007으로 나눈다.
=> 제일 간단한 방법이지만, N값이 크면 이항계수 (N, K)의 값을 저장할 방법이 없다.
2) "페르마의 소정리"을 이용해서 값을 구한다.
=> ap-1 ≡ 1 (mod p) {단, p: 소수, a: 정수}
소스코드:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
#include <iostream>
#define P 1000000007LL
#define MAX_SIZE 4000001
typedef long long ll;
// inv[x]의 정의는 x의 inverse가 아닌 x!의 inverse
ll fac[MAX_SIZE], n, k, inv[MAX_SIZE];
ll power(ll x, ll y) {
// x^0 인 경우, while로 들어가지 않는다.
ll ret = 1;
while (y > 0) {
// y % 2 == 1인 경우,
// y가 홀수인 경우
if (y % 2) {
ret *= x;
ret %= P;
}
// x 제곱
x *= x;
x %= P;
y /= 2;
}
return ret;
}
int main() {
// factorial 전처리
fac[1] = 1;
for (int i = 2; i < MAX_SIZE; i++) {
fac[i] = (fac[i - 1] * i) % P;
}
// 페르마의 소정리를 이용하여 fac(400만)의 inverse를 구함
// 이때 분할정복을 이용하여 logP의 시간에 처리
inv[MAX_SIZE - 1] = power(fac[MAX_SIZE - 1], P - 2);
for (int i = MAX_SIZE - 2; i >= 0; i--) {
// inverse(fac(i)) = inverse(fac(i + 1)) * (i + 1)
// 위의 수식을 이용하여 전처리
inv[i] = (inv[i + 1] * (i + 1)) % P;
}
// 총 O(N + logP)시간에 전처리
// 이후 어떤 쿼리가 들어와도 상수시간에
// 이항 계수를 1,000,000,007으로 나눈 나머지 계산 가능 std::cin >> n >> k;
// 예외처리 if (n == k || !k) {
printf("%d\n", 1);
return 0;
}
// 계산 ll r = (fac[n] * inv[n - k]) % P;
r = (r * inv[k]) % P;
printf("%lld\n", r);
return 0;
}
|
cs |
한줄평:
계산시간을 고려한 수학적인 접근 방식에 대해 많이 알아야겠다.
'알고리즘 > 백준' 카테고리의 다른 글
1300번 - K번째 수 (0) | 2021.03.30 |
---|---|
2110번 - 공유기 설치 (0) | 2021.03.29 |
1676번 - 팩토리얼 0의 개수 (0) | 2021.01.20 |
1181번 - 단어 정렬 (0) | 2020.08.09 |
2108번 - 통계학 (0) | 2020.08.08 |