hdu4828

hdu4828_第1张图片

题目链接

hdu4828

题目概述

        有一个 2 ∗ N 2*N 2N的格子,现在将 1   2 N 1~2N 1 2N 2 N 2N 2N个数放到这些格子中,每个格子放一个数,要求每一行后一个总比前一个大,每一列后面的比前面的大,即 a i j < a ( i + 1 ) j , a i j < a i ( j + 1 ) a_{ij} < a_{(i+1)j}, a_{ij} < a_{i(j+1)} aij<a(i+1)j,aij<ai(j+1).其中测试的组数 T ( 1 ≤ T ≤ 1 0 5 ) , T(1 \leq T \leq 10^5), T(1T105),数据 N ( 1 ≤ N ≤ 1 0 6 ) N(1 \leq N \leq 10^6) N(1N106).

解题思路

         C a t a l a n Catalan Catalan数取模计算的裸题,是<组合数学>这本书课后习题的第二个习题.因为这里模数 M = 1 0 9 + 7 M=10^9+7 M=109+7是一个素数,可以用扩展欧几里得计算出逆元,然后用第二个公式 C n = 4 ∗ n − 2 n + 1 C n − 1 C_n=\frac{4*n-2}{n+1}C_{n-1} Cn=n+14n2Cn1打表计算.

代码实现

#include
using namespace std;
typedef long long ll;
const int N = 1e6+5;
const int M = 1e9+7;
ll C[N];
// 扩展欧几里得
void extend_gcd(ll a, ll b, ll &x, ll &y){
    if (b == 0){
        x = 1;
        y = 0;
        return;
    }
    extend_gcd(b, a % b, x, y);
    ll temp = x;
    x = y;
    y = temp - (a / b) * y;
}
// 求逆元
ll mod_inverse(ll a, ll m){
    ll x, y;
    extend_gcd(a, m, x,y);
    return (m + x % m)% m;
}

// 打表用递推式计算C_n
void calculate(){
    C[0] = 1;
    for (int i = 1; i < N; i++){
        C[i] = (C[i - 1] * (4 * i - 2)) % M;
        C[i] = (C[i] * mod_inverse(i + 1, M)) % M;
    }
}

int main(int argc, const char** argv) {
    calculate();
    int n = 0;
    int t;
    scanf("%d", &t);
    for (int i = 0; i < t; ++i){
        scanf("%d", &n);
        printf("Case #%d:\n%lld\n", i+1, C[n]);
    }
    return 0;
}

其它

你可能感兴趣的:(Catalan数,逆元)