Bootstrap

火车进出栈问题 卡特兰数

问题 B: 火车进出栈问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 41  解决: 9
[提交] [状态] [讨论版] [命题人:admin]

题目描述

一列火车n节车厢,依次编号为1,2,3,…,n。每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。

输入

一个数,n(n<=60000)

输出

一个数s表示n节车厢出栈的可能排列方式

样例输入

3

样例输出

5

[提交][状态]

典型的卡特兰数例子,但是阶乘要用质因数分解(算术基本定理)来算,不然会T

\frac{1}{n+1}C\binom{n}{2n}  将上下阶乘质因数分解,然后约掉相同的质因数之后再乘,最后再除 n+1

用java写的大数,(纪念第一次完全自己写的java大数)

代码:

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(){
        for(int i=0; i<maxn; i++)
            f[i] = false;
        f[1] = true;
        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++){
            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);
    }
}

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

C_{n}=C_{0} \times C_{n-1} + C_{1} \times C_{n-2}+\cdots \cdots + C_{n-1}\times C_{0}     

#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;
}

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;