菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
321
0

卡特兰数

原创
05/13 14:22
阅读数 73079

卡特兰数是一种经典的组合数,前几项为:

1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796,58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...

计算公式为:h(n)=C(2n,n)/(n+1)

令h(0)=1,h(1)=1;

卡特兰数的递推式:h(n)= h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)。

//35以内的卡特兰数
void init() {
    long long h[36];
    h[0] = h[1] = 1;
    for (int i = 2; i < 36; i++) {
        h[i] = 0;
        for (int j = 0; j < i; j++)
        h[i] = h[i] + h[j] * h[i - j - 1];
    }
}

大于35时,求h(n)%p,用卢卡斯定理

h(n) % p = (Lucas(2n, n, p) - Lucas(2n, n - 1, p) + p) % p

ll exp_mod(ll a, ll b, ll p) {
    ll res = 1;
    while (b) {
        if (b & 1) res = (res * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return res;
}
ll comb(ll a, ll b, ll c) {
    if (a < b) return 0;
    if (a == b) return 1;
    if (b > a - b) b = a - b;
    ll ans = 1, ca = 1, cb = 1;
    for (ll i = 0; i < b; i++) {
        ca = (ca * (a - i)) % p;
        cb = (cb * (b - i)) % p;
    }
    ans = (ca * exp_mod(cb, p - 2, p)) % p;
    return ans;
}
ll lucas(ll n, ll m, ll p) {
    //Lucas求C(n,m)
    ll ans = 1;
    while (n && m && ans) {
        ans = (ans * comb(n % p, m % p, p)) % p;
        n /= p;
        m /= p;
    }
    return ans;
}

求卡特兰大数

int a[101][101], b[101];
//b[i]保存的是第i位卡特兰数的长度
//a[i]数组保存的是第i位卡特兰数的数值,高位存高位,低位存低位
void catalan() {
    int len, carry, temp;
    a[1][0] = b[1] = 1;
    len = 1;
    for (int i = 2; i <= 100; i++) {
        for (int j = 0; j < len; j++)
            a[i][j] = a[i - 1][j] * (4 * (i - 1) + 2);
        carry = 0;
        for (int j = 0; j < len; j++) {
            temp = a[i][j] + carry;
            a[i][j] = temp % 10;
            carry = temp / 10;
        }
        while (carry) {
            a[i][len++] = carry % 10;
            carry /= 10;
        }
        carry = 0;
        for (int j = len - 1; j >= 0; j--) {
            temp = carry * 10 + a[i][j];
            a[i][j] = temp / (i + 1);
            carry = temp % (i + 1);
        }
        while (!a[i][len - 1]) len--;
        b[i] = len;
    }
}

 

#include <iostream>
using namespace std;
int a[105][100];
int main( ) {
    int n,len;
    memset(a,0,sizeof(a));
    a[1][1]=1;
    a[1][0]=1; //a[n][0] 保存长度
    a[2][1]=2;
    a[2][0]=1;
    len=1;
    for(int i=3; i<=100; i++) {
        int yu(0),t;
        for(int j=1; j<=len; j++) { //乘的模拟
            t=(a[i-1][j])*(4*i-2)+yu;
            a[i][j]=t%10;
            yu=t/10;
        }
        while(yu) {
            a[i][++len]=yu%10;
            yu/=10;
        }
        for(int j=len; j>=1; j--) {  //除的模拟
            t=a[i][j]+yu*10;
            a[i][j]=t/(i+1);
            yu=t%(i+1);
        }
        while(!a[i][len]) len--;
        a[i][0]=len;
    }
    while(cin>>n) {
        for(int i=a[n][0]; i>0; i--)
        cout<<a[n][i];
        cout<<endl;
    }
    return 0;
}
View Code

 

发表评论

0/200
321 点赞
0 评论
收藏