卡特兰数 Catalan 笔记
一.公式
卡特兰数一般公式
令h(0)=1,h(1)=1,catalan数满足递推式。h(n) = h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)。也就是说,如果能把公式化成上面这种形式的数,就是卡特兰数。
组合公式
Cn = C(2n,n) / (n+1)
(化简前 h(n) = c(2n,n)-c(2n,n+1) (n=0,1,2,...) 证明)
递归公式1
h(n) = h(n-1)*(4*n-2) / (n+1)
递归公式2
h(n) = ∑(i=0 to n-1) h(i)*h(n-i-1)
二.资料
三.某些题
1.在圆上选择2n个等间隔的点。证明将这些点成对连接起来使得所得到的n条线段不相交的方法数等于第n个Catalan数
设方法数为gn,分别将这些点用1,2,…,2n标记。取定点1,任选另一个偶数点2k,连接点1与点2k。该线段将圆分成K1和K2两部分。对K1,有k-1对点,故有gk-1种方法;对K2,有n-k对点,故有gn-k种方法。所以
g0=1
令hn=gn-1,则
hn+1=h1hn+h2hn-1+…+hnh1 h1=1
所以gn=g0 gn-1 + g1 gn-1 +...+ gn-1 g0
即 gn=Cn
2.二叉树计数:一个有n个结点的二叉树总共有多少种形态
1 //设当前根节点为k,方案数为h[k],左子树有k-1个节点,右子树有n-k个节点 2 //则 h[k]=h[k-1]*h[n-k](k=1 to n) 3 //Ans= h[0]h[n-1] + h[1]h[n-2] +...+ h[n-1][0] 4 //即卡特兰数 5 #include<cstdio> 6 #include<cctype> 7 using namespace std; 8 const int N=22; 9 10 int n; 11 long long H[N]; 12 13 int read() 14 { 15 int now=0;bool f=0;char c=getchar(); 16 for(;!isdigit(c);c=getchar()) 17 if(c=='-') f=1; 18 for(;isdigit(c);c=getchar()) 19 now=(now<<3)+(now<<1)+c-'0'; 20 return f?-now:now; 21 } 22 23 int main() 24 { 25 n=read(); 26 H[0]=1; 27 for(int i=1;i<=n;++i) 28 H[i]=H[i-1]*(4*i-2)/(i+1); 29 printf("%lld",H[n]); 30 return 0; 31 }
3.出栈次序:一个栈(无穷大)的进栈次序为1、2、3……n。不同的出栈次序有几种。
我们可以这样想,假设k是最后一个出栈的数。比k早进栈且早出栈的有k-1个数,一共有h(k-1)种方案。比k晚进栈且早出栈的有n-k个数,一共有h(n-k)种方案。所以一共有h(k-1)*h(n-k)种方案。显而易见,k取不同值时,产生的出栈序列是相互独立的,所以结果可以累加。k的取值范围为1至n,所以结果就为h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)。(转自Blog)
1 //设k为最后一个出栈的数, 2 //有k-1个比k早进栈且比k早出栈,有C[k-1]种方案 3 //有n-k个比k晚进栈但比k早出栈,有C[n-k]种方案 4 //根据乘法原理,C[k]=C[k-1]*C[n-k](k=1 to n) 5 //Ans = C[0]C[n-1] + C[1][n-2] +...+ C[n-1][0] 6 #include<cstdio> 7 using namespace std; 8 const int N=22; 9 10 int n; 11 long long Ca[N]; 12 13 int main() 14 { 15 scanf("%d",&n); 16 Ca[0]=1; 17 for(int i=1;i<=n;++i) 18 Ca[i]=Ca[i-1]*(4*i-2)/(i+1); 19 printf("%lld",Ca[n]); 20 return 0; 21 }
注:
long long最大只能到33
Code:
1 Ca[0]=1; 2 for(int i=1;i<=n;++i) 3 Ca[i]=Ca[i-1]*(4*i-2)/(i+1);
高精:
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 using namespace std; 5 const int p=4,mod=10000; 6 7 int C[50005]; 8 9 inline int read() 10 { 11 int now=0;bool f=0;char c=getchar(); 12 for(;!isdigit(c);c=getchar()) 13 if(c=='-') f=1; 14 for(;isdigit(c);c=getchar()) 15 now=(now<<3)+(now<<1)+c-'0'; 16 return f?-now:now; 17 } 18 19 void Print(int n[]) 20 { 21 printf("%d",n[n[0]]); 22 for(int i=n[0]-1;i;--i) 23 printf("%0*d",p,n[i]); 24 puts(""); 25 } 26 void Mult(int n[],int t) 27 { 28 int x=0; 29 ++n[0]; 30 for(int i=1;i<=n[0];++i) 31 { 32 n[i]=n[i]*t+x; 33 // printf("%d:%d\n",i,n[i]); 34 x=n[i]/mod; 35 n[i]%=mod; 36 } 37 while(!n[n[0]] && n[0]>1) --n[0]; 38 // Print(n); 39 } 40 void Div(int n[],int t) 41 { 42 int x=0; 43 for(int i=n[0];i;--i) 44 { 45 n[i]=x*mod+n[i]; 46 x=n[i]%t; 47 n[i]/=t; 48 } 49 while(!n[n[0]] && n[0]>1) --n[0]; 50 // Print(n); 51 } 52 53 int main() 54 { 55 int n=read(); 56 C[0]=1; 57 C[1]=1; 58 for(int i=1;i<=n;++i) 59 { 60 // C[now]=C[now-1]*(4*i-2)/(i+1); 61 // printf("\n%d:\n",i); 62 Mult(C,4*i-2); 63 Div(C,i+1); 64 // Print(C); 65 } 66 Print(C); 67 return 0; 68 }
------------------------------------------------------------------------------------------------------------------------
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------