卡特兰数是组合数学中一个常出现在各种计数问题中的数列。
举个栗子: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, …。
设h(n)为catalan数的第n+1项,令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)
例如:h(2)=h(0) * h(1)+h(1) * h(0)=1 * 1+1 * 1=2
h(3)=h(0) * h(2)+h(1) * h(1)+h(2) * h(0)=1 * 2+1 * 1+2 * 1=5
另类递推式:
h(n)=h(n-1) * (4*n-2)/(n+1);
递推关系的解为:
h(n)=C(2n,n)/(n+1) (n=0,1,2,…)
递推关系的另类解为:
h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,…)。
举个栗子:n个节点的二叉树的构成有多少种情况。
h(0)=1
先考虑一个h(1)=1明显。
两个节点的时候,h(2)=h(1)+h(0)=2;
我们推广到一般的情况,n个节点的二叉树的情况分析,根节点是一定有的,只要去考虑左子树以及右子树的情况,左子树为0时h(0)*h(n-1),左子树有1个节点的时候h(1)*h(n-2),以此类推,根节点的左子树视作另一个根节点。即h(n)= h(0) * h(n-1)+h(1) * h(n-2) + … + h(n-1) * h(0) (n>=2)。
超级卡特兰数:click
题目:click
题意:先考虑对角线一边,另一边直接乘以2即可。
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 1 |
1 | – | 1 | 2 | 3 | 4 |
2 | – | – | 2 | 5 | 9 |
3 | – | – | – | 5 | 14 |
4 | – | – | – | – | 14 |
因为考虑的是最短路径所以一个劲的往右或者往下就是贡献。
dp[i][j]=dp[i-1][j]+dp[i][j-1];
而对角线的数即是卡特兰数。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=998244353;
ll dp[40][40];
int main()
{
ll i,j,k;
memset(dp,0,sizeof(dp));
for(i=0;i<=40;i++)
dp[0][1]=1;
for(i=1;i<=40;i++)
{
for(j=i;j<=40;j++)
{
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
int n;
int yy=1;
while(scanf("%d",&n)&&n!=-1)
{
printf("%d %d %lld\n",yy++,n,dp[n+1][n+1]*2);
}
return 0;
}