Coding/Baekjoon

[백준][파이썬]11401번 - 이항 계수 3

seomj 2022. 5. 2. 19:35

문제

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

입력

첫째 줄에 N K가 주어진다. (1 ≤ N ≤ 4,000,000, 0 ≤ K  N)

출력

 (NK)를 1,000,000,007로 나눈 나머지를 출력한다.


필요한 개념 및 알고리즘

dp

https://velog.io/@chelsea/1-%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95Dynamic-Programming-DP

 

[자료구조와 알고리즘] 동적 계획법(Dynamic Programming, DP)

동적 계획법(Dynamic Programming) - 컴퓨터 공학 스터디 W1 자료구조와 알고리즘 내용에 앞서 학교에서 컴퓨터 공학 이론 스터디를 진행하고 있습니다. 매주 발표하는 내용을 시리즈로 업로드할 예정

velog.io

 

분할정복

https://janghw.tistory.com/entry/알고리즘-Divide-and-Conquer-분할정복

 

[알고리즘] Divide and Conquer (분할정복)

분할정복 정의 : 분할정복 알고리즘은 문제를 나눌 수 없을 때까지 나누어서 각각을 풀면서 다시 합병하여 문제의 답을 얻는 알고리즘이다. 알고리즘을 설계하는 요령 (1) Divide : 문제가 분할이

janghw.tistory.com

 

모듈러 연산

 

 

파르마의 소정리

https://youtu.be/RLVW9XrvjhM

 

 

풀이

이항 계수 공식

N의 최대 입력 값이 매우 크기때문에 조건에 따라 1,000,000,007로 나눠줘야 한다.

이를 p로 두자.

모듈러 연산은 분수꼴에 적용할 수 없기때문에 곱셈꼴로 변경해주어야 한다.

 

이에 페르마의 소정리가 사용된다.

위의 식을 계산하기 위해 k!(n-k)! % p의 역원을 구해야 한다.

p가 소수이고 a가 p의 배수가 아니면

위 공식이 성립한다.

이를 변형하면

즉, (k!(n-k)!)-1 % p = (k!(n-k)!)p-2  % p 가 된다.

 

# 페르마의 소정리 이용

# 분할 정복을 이용하여 a^b를 구한다.
def power(a, b):
    if b == 0:
        return 1
    if b % 2:  # 홀수이면
        return (power(a, b // 2) ** 2 * a) % p
    else:
        return (power(a, b // 2) ** 2) % p


p = 1000000007
N, K = map(int, input().split())

# nCk를 나타내기 위해 팩토리얼을 dp로 구해줍니다.
fact = [1 for _ in range(N + 1)]

for i in range(2, N + 1):
    fact[i] = fact[i - 1] * i % p

# A는 nCk의 분자가되고 B는 분모가 됩니다.
A = fact[N]
B = (fact[N - K] * fact[K]) % p

#여기서 페르마의 소정리가 사용됨
print((A % p) * (power(B, p - 2) % p) % p)

아직 코드가 다 이해되지 않아 더 고민하고 추가 포스팅을 할 예정이다.

 

 

 

출처

https://my-coding-notes.tistory.com/94

https://rhdtka21.tistory.com/123

https://kyun2da.github.io/2020/08/30/BinomialCoefficient/