卡特兰数是一个很常见的数列,以比利时的数学家欧仁·查理·卡塔兰 (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, ...(摘自百度百科)
卡特兰数的求解方法
1.最基本的n^2递推
例题:https://www.luogu.org/problemnew/show/P1044
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n; 5 int f[20]; 6 int main() 7 { 8 scanf("%d",&n); 9 f[0]=1; 10 f[1]=1,f[2]=2; 11 for(int i=3;i<=n;++i) 12 for(int j=0;j<i;++j) 13 f[i]+=f[j]*f[i-j-1]; 14 cout<<f[n]<<endl; 15 return 0; 16 }
此题由于数据范围非常小,既不会t也不会炸int,所以直接n^2求即可。证明不会qwq。
2.卡特兰数的第n项h(n)=C(2n,n)-C(2n,n-1),所以用求组合数的方法求卡特兰数即可,针对对一个大质数取模的代码
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n,p; 5 int js[100005]; 6 int prime[100005]; 7 bool vis[100005]; 8 int cnt[100005]; 9 int qpow(int a,int b)//快速幂求逆元 10 { 11 int ans=1; 12 while(b) 13 { 14 if(b&1)ans=(1ll*a*ans)%p; 15 a=(1ll*a*a)%p; 16 b>>=1; 17 } 18 return ans; 19 } 20 int main() 21 { 22 scanf("%d%d",&n,&p);//求第n项,对p取模的结果,p为大质数 23 js[0]=1; 24 for(int i=1;i<=2*n;++i) 25 js[i]=(1ll*js[i-1]*i)%p; 26 int a=qpow(1ll*js[n]*js[n]%p,p-2),b=qpow(1ll*js[n-1]*js[n+1]%p,p-2); 27 a=1ll*a*js[2*n]%p,b=1ll*b*js[2*n]%p; 28 int ans=(a-b+p)%p;//a=C(2n,n)%p,b=C(2n,n-1)%p 29 printf("%d",ans); 30 return 0; 31 }
3.我们可以由第一种求法看出来卡特兰数增长的是很快的,所以当要求的项数比较大而且不能取模时,需要用到高精,这时分解质因数求卡特兰数就是一个很好的方法。
例题:https://www.luogu.org/problemnew/show/P2532
这题蒟蒻做的时候看到样例输入3,输出5,直接想到卡特兰数,没想到是对的,233333333
代码
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n; 5 int prime[1500],cnt; 6 bool vis[1550]; 7 int tong[1050]; 8 int ans[1100],len; 9 void cheng(int x,int sum)//高精乘低精 10 { 11 while(sum--) 12 { 13 for(int i=1;i<=len;++i)ans[i]*=x; 14 for(int i=1;i<=len;++i) 15 { 16 if(ans[i]>9) 17 { 18 ans[i+1]+=ans[i]/10,ans[i]%=10; 19 if(i+1>len)len++; 20 } 21 } 22 } 23 } 24 int main() 25 { 26 scanf("%d",&n); 27 vis[0]=vis[1]=1; 28 for(int i=2;i<=2*n;++i)//分解质因数 29 { 30 if(!vis[i])prime[++cnt]=i; 31 for(int j=1;j<=cnt&&prime[j]*i<=2*n;++j) 32 { 33 vis[i*prime[j]]=1; 34 if(i%prime[j]==0)break; 35 } 36 } 37 for(int i=1;i<=cnt;++i) 38 { 39 int tmp=2*n; 40 while(tmp/prime[i]>0)tong[i]+=tmp/prime[i],tmp/=prime[i]; 41 tmp=n;while(tmp/prime[i]>0)tong[i]-=tmp/prime[i],tmp/=prime[i]; 42 tmp=n+1;while(tmp/prime[i]>0)tong[i]-=tmp/prime[i],tmp/=prime[i]; 43 } 44 ans[1]=1,len=1; 45 for(int i=1;i<=cnt;++i) 46 { 47 if(tong[i]) 48 { 49 cheng(prime[i],tong[i]); 50 } 51 } 52 for(int i=len;i>=1;i--)printf("%d",ans[i]); 53 return 0; 54 }
4.卡特兰数的递推公式h(n)=h(n-1)*(4*n-2)/(n+1),不过蒟蒻因为不是很懂,总是觉得没谱,所以从来没有用过这个递推式。