티스토리 뷰

728x90
반응형

 

 

문제

 

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

 

입력

 

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

 

출력

 

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

 

풀이

 

이 문제를 풀기 위해선 사전지식이 두 개 필요하다.

 

하나는 이항 계수 (NK)의 계산 방법인데, 이는 아래와 같다.

 

n!k!(nk)!

 

두 번째는 페르마의 소정리인데, a가 정수, p가 소수일 때 수식으로 나타내면 아래와 같으며

 

ap11(modp)

 

위 식은 ap1p로 나누면 나머지가 1이 된다는 것을 의미한다. 여기서 양 변을 a로 나눠주면 다음과 같은데,

 

ap21a(modp)

 

즉, 위 조건을 만족하는 수의 경우 ap2를 p로 나누면 자기 자신의 역원(a1)이 된다는 뜻이며,

 

이를 이용하면 빠르게 r!×(nr)!의 역원을 구할 수 있다.

 

나머지는 직전 문제에서 풀었던 고속 거듭제곱을 이용하면 된다. 알고리즘의 순서는 다음과 같다.

 

  1. 입력으로 주어지는 n과 k를 받아 저장하고, n!까지의 값을 factorial 배열(리스트)에 미리 저장해 둔다.
  2. 문제의 조건에서 주어진 1000000007은 소수이므로 페르마의 소정리에 이용하기 위해 p에 저장한다.
  3. n!k!(nk)!의 분모 k!(nk)!를 빠르게 구하기 위해 k!(nk)!(modp)를 denominator에 저장한다.
  4. 이어서 1k!(nk)!denominatorp2로 치환한 뒤 고속 거듭제곱 함수 power를 호출한다.
    1. 지수가 1이 될 때까지 거듭제곱의 지수를 반으로 나누어 문제를 분할해 자기 자신을 아래와 같이 호출한다.
      long half = pow(base, exponent / 2);
      여기서 half는 int 범위를 넘어설 수 있기 때문에 long으로 선언해주어야 한다.
    2. 지수가 1이 된 경우 병합과정이 시작된다. 각 단계에서 지수가 짝수인 경우엔 half2(modp) 를,
      지수가 홀수인 경우엔 ((half2(modp))×base)(modp) 를 계산한다.
  5. 계산 결과인 n!×denominatorp2를 출력한다.

 

Java

 

package BackJoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Prob11401 {

	static final long p = 1000000007;

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		int n = Integer.parseInt(st.nextToken());
		int k = Integer.parseInt(st.nextToken());

		long[] factorial = new long[n + 1];
		factorial[0] = 1;
		factorial[1] = 1;

		for (int i = 2; i <= n; i++) {
			factorial[i] = (factorial[i - 1] * i) % p;
		}

		long denominator = (factorial[k] * factorial[n - k]) % p;

		System.out.println((factorial[n] * power(denominator, p - 2)) % p);

	}

	private static long power(long base, long exponent) {

		if (exponent == 1) {
			return base % p;
		}

		long half = power(base, exponent / 2);

		if (exponent % 2 == 0) {
			return (half * half) % p;
		} else {
			return (((half * half) % p) * base) % p;
		}
	}
}

 

Python

 

import sys

n, k = map(int, sys.stdin.readline().rstrip().split())
p = 1000000007

fac = [0] * (n + 1)
fac[0] = fac[1] = 1

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

denominator = (fac[k] * fac[n - k]) % p


def power(base, exponent):
    if exponent == 1:
        return base % p

    half = power(base, exponent // 2)

    if exponent % 2 == 0:
        return (half**2) % p
    else:
        return (((half**2) % p) * base) % p


print((fac[n] * power(denominator, p - 2)) % p)

 

Performance

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
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
글 보관함