Catalan Number

Posted perisino

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Catalan Number相关的知识,希望对你有一定的参考价值。

定义

这个cn啊,是组合数学里面经常会用到的东西,比如说:

  1. 让你算算二叉树的形态
  2. 又让你算算合法的括号序列
  3. 又或者让你算算出入栈的合法顺序
  4. 还可能让你去说说把多边形割成三角形方法

综上所述就是18年初赛的第8题

于是有的人弄出来了它的式子

我们设为f(n),那么有
[ f(n)=sum^{n-1}_{i=0}f(i)cdot f(n-i-1) ]
当然人们并不会满足一个式子,于是就有了第二个
[ f(n)=f(n-1)cdot frac{4n-2}{n+1} ]
但是因为我们没有通项式,所以必须要一个一个的算
与是通项式就来了
[ f(n)=frac{C^{n}_{2n}}{n+1} ]
当然如果我们进行一点变换的话就可以得到它:
[ f(n)=C^{n}_{2n}-C^{n-1}_{2n} ]

这个式子是一个好式子,面对问题是往往很容易就可以化成这一个形式,然后就发现了这是卡特兰数的题

例题

1.栈(洛谷P1044)

洛谷P1044
这一道题很容易就可以看出来这一个是Cn的模板题
那么就是这样的了
贴代码(用的是第二个式子)

//洛谷的卡特兰数模板题 
#include<bits/stdc++.h>
using namespace std;
long long f[20];

void getcn(int n){
    f[1]=1;
    for(int i=2;i<=n;i++){
        f[i]=((4*i-2)*f[i-1])/(i+1);
    }
    printf("%lld
",f[n]);
    return ;
}
int main(){
    int n;
    scanf("%d",&n);
    getcn(n);
    return 0; 
}

2.矩阵(洛谷P1722)

洛谷P1722
这一道题啊,可以看出来是一道卡特兰数的题,要求我们去模100,那么向第一个式子那样没有除法,只有加和乘的方法自然就是首选了,既然如此就用第一种方法写Cn就行了

//矩阵 洛谷P1722 
#include<bits/stdc++.h>
#define Mod 100
using namespace std;
int n;
long long f[105];
void solve(){
    f[0]=f[1]=1;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=i-1;j++){
            (f[i]+=f[j]*f[i-j-1])%=Mod;
        }
    }
    printf("%lld",f[n]);
    return;
}
int main(){
    scanf("%d",&n);
    solve();
    return 0;
} 

3.树屋阶梯(洛谷P2532)

洛谷P2532
这一道题啊,首先你这么考虑,任意选中其中一阶阶梯,然后呢就把整个阶梯分成了它上面的阶梯和它右面的阶梯。每一阶阶梯都这么去考虑,写出整个式子就会发现是卡特兰数了

//洛谷P2532 树屋
//这道题不得不用高精度了 
#include<bits/stdc++.h>
#define maxn 1000
using namespace std;
struct Ln{ // 整数,最大可存储一万位数字  
    int val[maxn];
    int operator [](const int &ref)const{
        return val[ref];
    }
    
    inline void Lin(){ // 读入  
        char S[maxn];
        scanf("%s",S);
        memset(val,0,sizeof(val));
        int lenS=strlen(S);
        val[0]=lenS;
        for(int i=lenS-1,j=1;i>=0;i--,j++) val[j]=S[i]-'0';
    }
    
    inline void StrIn(char *S){
        memset(val,0,sizeof(val));
        int lenS=strlen(S);
        val[0]=lenS;
        for(int i=lenS-1,j=1;i>=0;i--,j++) val[j]=S[i]-'0';
    }
    
    inline void Lout(){ // 输出  
        for(int i=val[0];i>=1;i--)
         putchar(val[i]+'0');
    }
    
    bool operator ==(const Ln &obj)const{ // 判断是否等于  
        if(val[0]!=obj[0]) return false;
        for(int i=1;i<=val[0];i++) if(val[i]!=obj[i]) return false;
        return true;
    }
    
    bool operator <(const Ln &obj)const{ // 判断是否小于   
        if(val[0]>obj[0]) return false;
        if((*this)==obj) return false;
        if(val[0]<obj[0]) return true;
        for(int i=val[0];i>=1;i--){
            if(val[i]>obj[i]) return false;
            if(val[i]<obj[i]) return true;
        }
        return true;
    }
    
    bool operator >(const Ln &obj)const{ // 判断是否大于   
        Ln cmp=*this;
        if(cmp < obj || cmp == obj) return false;
        return true;
    }
    
    Ln operator +(const Ln &obj)const{ // 加法运算  
        Ln cmp;
        memset(cmp.val,0,sizeof(cmp.val));
        int pos=max(val[0],obj[0]),add=0;
        for(int i=1;i<=pos;i++){
            cmp.val[i]=val[i]+obj[i]+add;
            add=cmp.val[i]/10;
            cmp.val[i]=cmp.val[i]%10;
        }
        if(add>0) cmp.val[++pos]=add;
        cmp.val[0]=pos;
        return cmp;
    }
    
    Ln operator -(const Ln &obj)const{ // 减法运算 只能减出正数  
        Ln cmp;
        memset(cmp.val,0,sizeof(cmp.val));
        int pos=val[0],rent=0; // rent 借位  
        for(int i=1;i<=pos;i++){
            cmp.val[i]=val[i]-obj[i]-rent;
            if(cmp.val[i]<0) {cmp.val[i]+=10;rent=1;}
            else rent=0;
        }
        while(cmp.val[pos]==0 && pos>1) pos--;
        cmp.val[0]=pos;
        return cmp;
    }
    
    Ln operator *(const int &obj)const{ // 高精度 ×低精度 
        // 对于高精度数 a 和低精度数 b   
        // 这个算法可以写成 a=a^b 
        Ln cmp;
        memset(cmp.val,0,sizeof(cmp.val));
        int pos=val[0]; // 进位 
        long long add=0;
        for(int i=1;i<=pos;i++){
            cmp.val[i]=val[i]*obj+add;
            add=cmp.val[i]/10;
            cmp.val[i]=cmp.val[i]%10;
        }
        while(add>0){
            cmp.val[++pos]=add%10;
            add/=10;
        }
        while(cmp.val[pos]==0 && pos>1) pos--;
        cmp.val[0]=pos;
        return cmp;
    }
    
    Ln operator *(const Ln &obj)const{ // 高精度 ×高精度 
        // 对于高精度数 a 和高精度 b   
        // 这个算法不能写成 a=a*b 
        Ln cmp;
        memset(cmp.val,0,sizeof(cmp.val));
        int pos=val[0]+obj[0];
        for(int i=1;i<=val[0];i++){
            for(int j=1;j<=obj[0];j++){
                cmp.val[i+j-1]+=val[i]*obj[j];
                cmp.val[i+j]+=cmp.val[i+j-1]/10;
                cmp.val[i+j-1]=cmp.val[i+j-1]%10;
            }
        }
        while(cmp.val[pos]==0 && pos>1) pos--;
        cmp.val[0]=pos;
        return cmp;
    }
    
    Ln operator /(const int &obj)const{ // 高精度 ÷低精度  
        Ln cmp;
        memset(cmp.val,0,sizeof(cmp.val));
        int pos=val[0],div=0;
        for(int i=pos;i>=1;i--){
            cmp.val[i]=(div*10+val[i])/obj;
            div=(div*10+val[i])%obj;
        }
        while(cmp[pos]==0 && pos>1) pos--;
        cmp.val[0]=pos;
        return cmp;
    }
    
    int operator %(const int &obj)const{ // 高精度 % 低精度  
        int pos=val[0],div=0;
        for(int i=pos;i>=1;i--) div=(div*10+val[i])%obj;
        return div;
    }
    
    Ln operator /(const Ln &obj)const{ // 高精度 ÷高精度  
        Ln cmp,t_cmp;
        memset(cmp.val,0,sizeof(cmp.val));
        memset(t_cmp.val,0,sizeof(t_cmp.val));
        int pos=val[0];
        cmp.val[0]=1;cmp.val[1]=0;
        t_cmp=cmp;
        if((*this)<obj) return cmp; // 小于除数直接返回 0  
        for(int i=pos;i>=1;i--){
            t_cmp=t_cmp*10;
            t_cmp.val[1]=val[i];
            int k=0;
            while(t_cmp>obj || t_cmp==obj)
            {
                t_cmp=t_cmp-obj;
                k++;
            }
            cmp.val[i]=k;
        }
        while(cmp.val[pos]==0 && pos>1) pos--;
        cmp.val[0]=pos;
        return cmp;
    }
    
    Ln operator %(const Ln &obj)const{ // 高精度 % 高精度  
        Ln t_cmp;
        memset(t_cmp.val,0,sizeof(t_cmp.val));
        int pos=val[0];
        t_cmp.val[0]=1;t_cmp.val[1]=0;
        if((*this)<obj) return (*this); // 小于除数直接返回本身 
        for(int i=pos;i>=1;i--){
            t_cmp=t_cmp*10;
            t_cmp.val[1]=val[i];
            while(t_cmp>obj || t_cmp==obj) t_cmp=t_cmp-obj;
        }
        return t_cmp;
    }
};
Ln f[505]={{1,1}};
int n;
void solve(){
    f[1]=f[0];
    for(int i=2;i<=n;i++){
        f[i]=(f[i-1]*(4*i-2))/(i+1);
    }
    f[n].Lout();
} 
int main(){
    scanf("%d",&n);
    solve();
    return 0;
} 

以上是关于Catalan Number的主要内容,如果未能解决你的问题,请参考以下文章

Catalan Number-卡特兰数入门

Catalan Number

Asymptotic I Catalan Number

卡特兰数(Catalan number)

Catalan number (卡特兰数)

浅谈卡特兰数(Catalan number)的原理和应用