티스토리 뷰
https://www.acmicpc.net/problem/11401
이번 문제는 11050, 11051번 문제와는 달리 굉장히 큰 입력을 처리해야 합니다.
특히 ( 큰 수 / 큰 수 ) 를 실행해야 하는데 이는 쉽지 않으므로 간단한 방법을 생각해보겠습니다.
$$_{n}C_{k}\textrm{ mod }1000000007 = \frac{n!}{k!(n-k)!}\textrm{ mod 1000000007}$$
이 식을 풀어야 하는데 단순히 큰 수끼리의 나눗셈이 힘들기 때문에 페르마의 소정리를 이용한 분할정복법을 이용하겠습니다.
페르마의 소정리를 이용하여 위 식을 변형하기 위해서는 나머지연산 곱셈의 역원에 대해서 알아야 합니다.
분할정복
페르마의 소정리
나머지연산 곱셈의 역원
$$\begin{align*} a^{p-1}\equiv 1\\ a\times a^{p-2}\equiv 1\\ a\times x\equiv 1\\ \therefore x=a^{p-2} \end{align*}$$
변형된 nCk 나머지 연산
위 식을 약분하여 정리하면
$$n!\times (k!(n-k)!)^{m-2}\equiv x$$
이라는 식을 구할 수 있습니다.
위 식을 이용하면
$$[n!\times (k!(n-k)!)^{m-2}]\textit{ mod m }= (n!\textit{ mod m })\times [(k!(n-k)!)^{m-2}\textit{ mod m }]$$
이라는 식도 얻을 수 있습니다.
이제 이 식을 파이썬코드로 구현하겠습니다.
m = 1000000007 def x_y(x, y): xy = 1 while y > 0: if(y % 2) == 1: xy *= x y -= 1 xy %= m x *= x x %= m y /= 2 return xy
x_y(x, y) 함수는 거듭제곱을 계산하는 함수입니다.
그런데 거듭제곱수만큼 곱하는 것이 아니라 시간복잡도를 줄이기 위해서
$$a^{10} = (a^{5})^{2} = (a\times (a^{2})^{2})^{2}$$
와 같은 방법을 이용했습니다.
N, K = map(int, input().split()) r1 = 1 r2 = 1 for i in range(1, N+1): r1 *= i r1 %= m for i in range(1, K+1): r2 *= i r2 %= m for i in range(1, N-K+1): r2 *= i r2 %= m
입력 값을 각각 N, K에 저장합니다.
r1에는 분자 부분이 될 N!을 계산합니다.
r2에는 분모 부분이 될 K!(N-K)!을 계산합니다.
여기서 단순히 팩토리얼 계산만 하는 것이 아니라
$$(a\times b)\textit{ mod m }=(a\textit{ mod m })\times (b\textit{ mod m })$$
의 방법을 이용해서 수가 커지는 것을 방지합니다.
r2 = x_y(r2, m-2) r2 %= m r1 *= r2 r1 %= m print(r1)
$$n!\times (k!(n-k)!)^{m-2}\equiv x$$
마지막으로 이 식을 이용하여 나머지를 구한 후 출력하면 되겠습니다.
m = 1000000007 def x_y(x, y): xy = 1 while y > 0: if(y % 2) == 1: xy *= x y -= 1 xy %= m x *= x x %= m y /= 2 return xy N, K = map(int, input().split()) r1 = 1 r2 = 1 for i in range(1, N+1): r1 *= i r1 %= m for i in range(1, K+1): r2 *= i r2 %= m for i in range(1, N-K+1): r2 *= i r2 %= m r2 = x_y(r2, m-2) r2 %= m r1 *= r2 r1 %= m print(r1)
'알고리즘' 카테고리의 다른 글
[백준 알고리즘] 조합(2407) (0) | 2018.02.11 |
---|---|
[백준 알고리즘] 팩토리얼 0의 개수(1676) (0) | 2018.02.11 |
[백준 알고리즘] 팩토리얼(10872) (0) | 2018.02.11 |
[백준 알고리즘] 이항계수2(11051) (0) | 2018.02.10 |
[백준 알고리즘] 이항계수1(11050) (0) | 2018.02.09 |
- Total
- Today
- Yesterday
- wrap_content
- firestore
- activity
- 안드로이드 레이아웃
- Android Studio
- 안드로이드 스튜디오
- androidx
- 스튜디오
- 뒤로가기
- 에그타이머
- 안드로이드 여백
- RecyclerView Swipe
- 파이어스토어
- 프래그먼트
- android
- calendarView
- 액티비티
- RecyclerView 여백
- eggtimer
- java
- intent
- Alfred
- recyclrView
- 파이어베이스
- RecyclerView padding
- layout
- 레이아웃
- round border
- 안드로이드
- Firebase
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |