Posts 11401 이항계수 3
Post
Cancel

11401 이항계수 3

11401 이항계수 3

알고리즘(페르마의 소정리, 거듭제곱)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 페르마의 소정리 적용
	nCk = n! / k!(n-k)! % 1000000007 에서 A = n!, B = k!(n-k)!, p = 1000000007 이라고 할 때

	위 식은 (A * B^(-1)) % p 를 성립
	페르마의 소정리는 p가 소수일때, p와 서로소인 a가 있으면, a^p mod p = a mod p 가 성립. -> a^p-1 mod p = 1 mod p 이므로 a^p-1 mod p = 1 이 성립함을 알려주는 공식
	여기서 양변에 a를 한번 더 나누면
	a^p-2 mod p = a^(-1) 이 성립함을 알 수 있음
	따라서 위 이항 계수 식은 다음처럼 변형된다.
	(A * B^(-1)) % p = (A * B^(p-2)) % p
2. A = n!과 B = k!(n-k)! 를 구한 후, 거듭제곱 공식으로 B^(p-2)를 구하면 됨.


 A = n*...*(n-k+1), B = k! 로 두고 풀어도 됨
-> 처음에 틀렸던 이유는 (k!)^(p-2)가 아니라 (k)^(p-2)로 풀었기 때문

코드

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
#include <iostream>
#define DIVIDE 1000000007

using namespace std;

long long getCoefficient(int n, int k);
long long getPower(long long n, long long k);

int main() {
	int n, k;
	cin >> n >> k;
	cout << getCoefficient(n, k) << endl;

}

long long getCoefficient(int n, int k) {
	if (k == 0 || k == n)
		return 1;

	long long top = 1, bottom = 1, bottom2 = 1;

	for (int i = n; i >= 1; i--)
		top = (top * i) % DIVIDE;
	top %= DIVIDE;
	for (int i = k; i >= 1; i--)
		bottom = (bottom * i) % DIVIDE;
	bottom %= DIVIDE;
	for (int i = n - k; i >= 1; i--)
		bottom2 = (bottom2 * i) % DIVIDE;
	bottom2 %= DIVIDE;


	bottom = (bottom * bottom2) % DIVIDE;
	top %= DIVIDE;

	return (top * (getPower(bottom, DIVIDE - 2))) % DIVIDE;
}

long long getPower(long long n, long long k) {
	long long result = 1, temp = n;

	while (k > 0) {
		if (k % 2 == 1) {
			result = (result * temp) % DIVIDE;
		}
		temp = (temp * temp) % DIVIDE;
		k /= 2;
	}

	return result % DIVIDE;
}
This post is licensed under CC BY 4.0 by the author.

1107 리모컨

11437 LCA

Comments powered by Disqus.