반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
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
Archives
Today
Total
관리 메뉴

코딩하기 좋은날

백준 11401 이항계수 3 본문

백준(Baekjoon) 문제

백준 11401 이항계수 3

huiung 2020. 3. 12. 00:57
반응형

이 문제는 nCk를 구하는 문제이지만 n이 400만으로 굉장히 큽니다. 

 

이항계수는 보통 n이 작을때  nCk = n-1Ck-1 + nCk-1 다음과 같은식으로 동적계획법을 이용해서 구할 수 있지만 이경우 시간복잡도가 O(N^2)이 걸리게 됩니다. 따라서 이문제는 좀더 빠른 방법을 이용하여야 하는데

 

바로 nCk = n!/k!(n-k)! 식을 이용하는 겁니다. 

 

페르마의 소정리에 따라 n^p-1 = 1 (mod p) 임을 알고 있습니다. 

따라서 n^p-2 = n^-1 (mod p) 가되고 결론적으로 우리는 1 / k!(n-k)!  이라는 식을 k!(n-k)!^p-2라는 식으로 치환 할 수 있습니다. 

 

총 정리를 하면 

 

1. 1~n 까지 각 n! % MOD 를 구합니다. ( fac[] 배열)

2. n의 modular inverse를 분할정복을 통해 구합니다. n!^p-2 (inv[] 배열) (O(log p))

3. 이후 n 보다 작은 수들은  inv[a] = (inv[a+1]*(a+1))%mod 를 통해 구할 수 있습니다.

  -> inv[a+1] 이 (a+1)^-1 의 modular inverse 이므로 a+1을 곱해서 a!^-1 의 modular inverse를 구할 수 있습니다.

따라서 이러한 전처리 이후 O(1) 만에 nCk 를 구한는 것이 가능하고 위의 전처리 과정은 O(N)이 소요됨을 알 수 있습니다.

 

다음은 코드입니다.

 

#include <iostream>

using namespace std;

#define MOD 1000000007LL

long long fac[4000010];
long long inv[4000010];

/*
    페르마 소정리를 이용한 nCr 빠르게 구하기
    팩토리얼 % MOD 값을 먼저 전처리 한후
    각 팩토리얼의 modular inverse를 구함

    nCr = n!/k!(n-k)! 이므로 우리는 1 / k!(n-k)!을

    페르마 소정리에 따라 k!(n-k)!^MOD-2 으로 치환이 가능함.

*/

long long solve(long long x, long long y) {
    long long ret = 1;
    while(y > 0) {
        if(y%2) {
            ret *= x;
            ret %= MOD;
        }
        x *= x;
        x %= MOD;
        y /=2;
    }
    return ret;
}

int main(void) {
    ios_base::sync_with_stdio(false); cin.tie(NULL);
    int n,m; cin >> m >> n;

    fac[1] = 1;
    for(int i = 2; i <= m; i++) {
        fac[i] = (fac[i-1]*i)%MOD;
    }

    inv[m] = solve(fac[m], MOD-2); //각 팩토리얼의 modular inverse를 구함

    for(int i = m-1; i >= 1; i--)
        inv[i] = (inv[i+1]*(i+1))%MOD; // inv[i+1] -> (i+1)!^-1 이므로 i+1을 곱하면 (i)!^-1 가 됨.

    long long first = fac[m]*inv[m-n]%MOD;

    if(m == n || n == 0) cout<<1;
    else cout<< first*inv[n]%MOD;
    return 0;
}

 

 

반응형

'백준(Baekjoon) 문제' 카테고리의 다른 글

백준 14444 가장 긴 팰린드롬 부분 문자열  (0) 2020.03.22
백준 1786 찾기  (0) 2020.03.21
백준 1708 볼록 껍질  (0) 2020.02.13
백준 1613 역사  (0) 2020.01.29
백준 2225 합분해  (0) 2020.01.29