• 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;
    } 
    
    
  • 相关阅读:
    css 去除input框边框 鼠标禁用状态 背景颜色
    css 文字边框
    搭建简易的Vue项目
    那些年遇到的Bug
    vue 点击弹出下拉菜单 点击其他页面收回菜单
    css 控制文本显示
    css tips提示框 三角形 + 框
    vue 细节 规范(只要不断片,持续的更新.....)
    @click.self
    工欲善其事,必先利其器
  • 原文地址:https://www.cnblogs.com/perisino/p/10327399.html
Copyright © 2020-2023  润新知