Catalan数

Catalan 数

引入

Problem:

具有n个节点的二叉树的形态有多少种?

分析:

因为二叉树定义具有递归性,左子树有i个节点,那么右子树有n-i-1个节点,根据计数原理:
\[ f\left ( n \right )=\sum_{i=0}^{n-1}f\left ( i \right )\cdot f\left ( n-i-1 \right ),f\left ( 0 \right )=1,f\left ( 1 \right )=1 \]


Catalan数

这里的:
\[ f\left ( n \right )=\sum_{i=0}^{n-1}f\left ( i \right )\cdot f\left ( n-i-1 \right ) \]
就叫做卡特兰数,该数列的前若干项是:

1,2,5,14,42,132,429,1430....

所以增长速度是非常快的。

常见的Catalan数表达式

1、递推式:
\[ f\left ( n \right )=\sum_{i=0}^{n-1}f\left ( i \right )\cdot f\left ( n-i-1 \right ),f\left ( 0 \right )=1 \]
2、另类递推式:
\[ f\left ( n \right )=\frac{(4n-2)f\left ( n-1 \right )}{n+1} \]
3、通向式(重要,常用):
\[ f\left ( n \right )=\frac{C\begin{matrix} n\\ 2n \end{matrix}}{n+1} \]
4、通向式2:
\[ f\left ( n \right )=C\begin{matrix} n\\ 2n \end{matrix} -C \begin{matrix} n-1\\ 2n \end{matrix} \]

利用通向式求Catalan(n) Code
#define ll long long
ll Catalan(ll n){
    ll ans=1;
    for(ll i=n+1;i<=2*n;i++){
         ans=ans*i/(i-n);
         printf("%d %d %lld\n",i,i-n,ans);
    }
    return ans/(n+1);
}

应用:

•Cn表示n个节点不同形态的二叉树个数。

•Cn表示n的入栈序列对应的合法出栈序列的个数。(luogu P1044)

​ 变式:

​ •n个0和n个1,构造一个长度为2n的序列,使得序列的任意前缀中1的个数不 少于0的个数,这样的序列有多少种?

​ •n个矩阵相乘,用括号改边运算顺序,有多少种?(ps:n个矩阵相乘需要n-1对括号,再增加是无意义的)

​ •游乐园门票1元一张,每人限购一张。现在有10个小朋友排队购票,其中5个小朋友每人只有1元的钞票一张,另5个小朋友每人只有2元的钞票一张,售票员没有准备零钱。问:有多少种排队方法,使售票可以正常进行下去?

•凸多边形分割成三角形方案数

图像法

n·n的矩阵,每次只能往右或往上走1个单位,问从(0,0)走到n·n,且路线一直处于y=x之下的方法总数是多少?

只需要n步的向右和n步的向上就能到达(n,n)。为了不跨越y=x,需任意时刻向右的次数>=向上的次数,显然答案就是卡特兰数

扩展:几乎所有的卡特兰数的问题都可以用这样的折线法方式解答。比如入栈映射为向右,出栈映射成向上,任意时刻入栈次数>=出栈


例题-luogu P2532 [AHOI2012]树屋阶梯

Problem

Problem

Problem

Problem

分析

卡特兰数,注意N的取值范围,要用高精度

Code
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int maxn=10005;   
struct highprecc{
    int l,a[maxn];
    void init(){l=1;a[1]=1;}
    void out(){for(int i=l;i>=1;i--) printf("%d",a[i]);}
    highprecc operator * (const ll b) const{
        highprecc c;
        for(int i=1;i<=l;i++) c.a[i]=a[i]*b;
        for(int i=2;i<=l;i++){
            c.a[i]+=c.a[i-1]/10;
            c.a[i-1]%=10;
        }
        c.l=l;
        while(c.a[c.l]>10){
            c.a[c.l+1]=c.a[c.l]/10;
            c.a[c.l]%=10;
            c.l++;
        }
        return c;
    }
    highprecc operator / (const ll b) const{
        highprecc c;
        ll k=l,g=0;
        for(int i=l;i>0;i--){
            g=g*10+a[i];
            c.a[i]=g/b;
            g%=b;
        }
        while(k>1 && c.a[k]==0) k--;
        c.l=k;
        return c;
    }
};  
highprecc f(ll n){
    highprecc ans;ans.init();
    for(ll i=n+1;i<=2*n;i++) ans=ans*i/(i-n);
    return ans/(n+1);
}
int main(){
    ll n;scanf("%lld",&n);
    f(n).out();
    return 0;
}

转载于:https://www.cnblogs.com/saitoasuka/p/10329023.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值