火车进出栈问题 【求卡特兰数】
卡特兰数:
卡特兰数又称卡塔兰数,英文名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)=1,catalan数满足递推式 [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,...)
求卡特兰数:
- 数较小的情况下:
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;
}
- 数较大的情况下:(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);
}
}