Skip to content

M27217: 有多少种合法的出栈顺序

http://cs101.openjudge.cn/practice/27217/

cpp
#include <bits/stdc++.h>
using namespace std;

vector<int> ans = {1};
vector<int> prime;
int n, m, expo[1000], num;
bool b[2001];

vector<int> multiply(const vector<int>& ans, int x) {
    vector<int> c;
    int carry = 0;
    for (int i = 0; i < ans.size() || carry; i++) {
        if (i < ans.size()) carry += ans[i] * x;
        c.push_back(carry % 10);
        carry /= 10;
    }
    return c;
}

// 计算 n! 中质数 p 的指数(勒让德公式)
int getExponent(int n, int p) {
    int count = 0;
    while (n > 0) {
        n /= p;
        count += n;
    }
    return count;
}

int main() {
    scanf("%d", &n);
    
    // 筛法求素数
    memset(b, true, sizeof(b));
    for (int i = 2; i <= n * 2; i++) {
        if (b[i]) {
            prime.push_back(i);
            for (int j = i * i; j <= n * 2; j += i) {
                b[j] = false;
            }
        }
    }
    m = prime.size();
    
    // 计算卡特兰数的质因数分解
    // C_n = (2n)! / (n! * (n+1)!)
    for (int i = 0; i < m; i++) {
        int p = prime[i];
        // 分子:(2n)!
        expo[i] += getExponent(2 * n, p);
        // 分母:n! 和 (n+1)!
        expo[i] -= getExponent(n, p);
        expo[i] -= getExponent(n + 1, p);
    }
    
    // 根据质因数分解计算结果
    for (int i = 0; i < m; i++) {
        for (int j = 1; j <= expo[i]; j++) {
            ans = multiply(ans, prime[i]);
        }
    }
    
    // 输出结果
    for (int i = ans.size() - 1; i >= 0; i--) {
        printf("%d", ans[i]);
    }
    return 0;
}