火车进出栈问题 【求卡特兰数】

卡特兰数

卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名,其前几项为(从第零项开始) : 1, 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(0)=1,h(1)=1catalan数满足递推式 [2]  

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2)

例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2

h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

另类递推式 [3]  

h(n)=h(n-1)*(4*n-2)/(n+1);

递推关系的解为:

h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

递推关系的另类解为:

h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)

 

求卡特兰数:

  1. 数较小的情况下:

n小的话,还可以用卡特兰数的递推公式 

 

#include <bits/stdc++.h>

using namespace std;

const  int maxn=2e5+10;

#define INF 0x3f3f3f;

const int mod=998244353;

typedef long long ll;

int f[maxn];

int main()

{

    int n;

    cin>>n;

    f[0] = f[1] = 1;

    for(int i=2; i<=n; i++){

        for(int j=0; j<i; j++){

            f[i] += f[j] * f[i-j-1];

        }

    }

    cout<<f[n]<<endl;

    return 0;

}

     

  1. 数较大的情况下:(java大数代码)

 

用公式h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

将上下阶乘质因数分解,然后约掉相同的质因数之后再乘,最后再除 n+1

 

import java.math.BigInteger;

import java.util.Scanner;

 

 

public class Main {

    static Scanner cin = new Scanner(System.in);

    static final int maxn = 200100;

    static int[] prime = new int[maxn];

    static boolean[] f = new boolean[maxn];

    static int k;

    static void init(){ //欧拉筛

        k = 0;

        for(int i=2; i<=maxn; i++){

            if(f[i] == false)

                prime[k++] = i;

            for(int j=0; j<k && prime[j] * i < maxn; j++){

                f[prime[j]*i] = true;

                if(i % prime[j] == 0)  break;

            }

        }

    }

    static BigInteger qpow(int x,int b){

        BigInteger a = BigInteger.valueOf(x);

        BigInteger ret = BigInteger.valueOf(1);

        while(b != 0){

            if(b%2 == 1)  ret = ret.multiply(a);

            a = a.multiply(a);

            b >>= 1;

        }

        return ret;

    }

    public static void main(String args[]){

        int n;

        n = cin.nextInt();

        init();

        BigInteger ans = BigInteger.valueOf(1);

        int p,v;

        int cnt = 0;

        for(int i=0; i<k && prime[i] <= n*2; i++){ //2n/n!质因数相消

            cnt = 0;

            p = prime[i];

            v = n * 2;

            while(v > 0){

                cnt += v/p;

                v /= p;

            }

            v = n;

            while(v > 0){

                cnt -= v/p * 2;

                v /= p;

            }

            ans = ans.multiply(qpow(p,cnt));

        }

        BigInteger x = BigInteger.valueOf(n+1);

        ans = ans.divide(x);

        System.out.println(ans);

    }

}

 

posted @ 2019-02-25 22:03  zangzang  阅读(229)  评论(0编辑  收藏  举报