R&E: research & education/PS

백준 13977번 이항 계수와 쿼리 (boj/13977.c)

KMS studio 2024. 1. 21. 11:11

확장유클라디안 알고리즘으과 메모이제이션을 사용하는 문제입니다. 모든 팩토리얼에 대해 normal modular와 inverse modular를 계산한 뒤, 입력값에 따라 처리합니다.

시간복잡도는 N의 최대값을 N, 제수를 M이라 할 때 O(NlogM)입니다.

#include <stdio.h>
#include <math.h>
#define MOD_N   1000000007
#define MAX_N   4000000
typedef long long lint;
int mem[MAX_N+1] = { 0, };
int inv[MAX_N+1] = { 0, };
int EEA(int i, int m){
    int Q, Q1, Q2;
    int S, S1, S2;
    int T, T1, T2;
    int M;
    Q1=i; Q2=m;
    S1=T2=1; S2=T1=0;
    for(;;){
        Q=Q1/Q2; M=Q1%Q2;
        S=S1-S2*Q; T=T1-T2*Q;
        if(!M){ break; }
        Q1=Q2; Q2=M;
        S1=S2; S2=S;
        T1=T2; T2=T;
    }
    if(S2<0){ S2+=m; }
    return S2;
}
void init(int N){
    mem[0]=1; inv[0]=1;
    for(int i=1;i<=N;i++){
        mem[i] = (lint)mem[i-1]*i % MOD_N;
        inv[i] = EEA(mem[i], MOD_N); }
    return;
}
int main(void){
    int M, N, K;
    lint tmp;
    init(MAX_N);
    scanf("%d", &M);
    for(int i=0;i<M;i++){
        scanf("%d %d", &N, &K);
        tmp = (lint)mem[N] * inv[N-K] % MOD_N;
        tmp = tmp * inv[K] % MOD_N;
        printf("%d\n", (int)tmp);
    }
    return 0;
}