卡特兰数
一、卡特兰数
1、公式:\(K_{n}=C_{2n}^{n}-C_{2n}^{n-1}=\frac{C_{2n}^{n}}{n+1}=\frac{K_{n-1}(4n-2)}{n+1}(n\ge1)\),当 \(n==0\) 时,\(K_0=1\)。
2、特殊性质:卡特兰数是符合下面这个数列的一个公式:\(h(n)=h(0)h(n-1)+h(1)h(n-2)+...+h(n-1)h(0)\) \((其中n\ge 2,h(0)=h(1)=1)\)。
3、前几项为:\(0,1,2,5,14,...\),所以只要符合这个数列就是卡特兰数。
二、应用
1、卡特兰数解决的问题:
-
二叉树的构成计数问题:已知二叉树有 \(n\) 个结点,求能构成多少种不同的二叉树
-
括号化问题:一个合法的表达式由()包围,()可以嵌套和连接,如:(())()也是合法表达式,现给出 \(n\) 对括号,求可以组成的合法表达式的个数。
-
凸多边形的划分问题:将一个凸 \(n+2\) 多边形区域分成三角形区域的方法数。
-
进出栈问题:一个栈的进栈序列为 \(1,2,3,...n\),求不同的出栈序列有多少种。
q -
路径问题:在 \(n*n\) 的方格地图中,从一个角到另外一个角,求不跨越对角线的路径数有多少种。
-
握手问题:\(2n\) 个人均匀坐在一个圆桌边上,某个时刻所有人同时与另一个人握手,要求手之间不能交叉,求共有多少种握手方法。
三、代码
代码一解决不取模的:
template<typename T>
struct Catelan{
static const int N = 50;
T C[N + 1][N + 1];
Catelan() {
for (T i = 0; i <= N; i++) {
C[i][0] = C[i][i] = 1;
for (T j = 1; j < i; j++) {
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
}
}
inline T get(T n) {
return C[2 * n][n] / (n + 1);
}
};
解决取模的代码:
template<typename T>
struct Catelan{
inline T qp(T a, T b, T p = 1e9 + 7) {
T res = 1;
a %= p;
for (; b; b >>= 1LL, a = a * a % p) {
if (b & 1) res = res * a % p;
}
return res;
}
inline T get_inv(T a, T p = 1e9 + 7) {
return qp(a, p - 2, p);
}
int N;
vector<T> fac, inv;
Catelan() {}
Catelan(int N_, T p = 1e9 + 7) : fac(N_ + 1), inv(N_ + 1) {
N = N_;
fac[0] = 1;
for (T i = 1; i <= N; i++) fac[i] = fac[i - 1] * i % p;
inv[N] = get_inv(fac[N], p);
for (T i = N - 1; i >= 1; i--) inv[i] = inv[i + 1] * (i + 1) % p;
}
inline T C(T n, T m, T p = 1e9 + 7) {
if (n < m) {
return (T)0;
}
return fac[n] * inv[n - m] % p * inv[m] % p;
}
inline T get(T n, T p = 1e9 + 7) {
return (C(2 * n, n, p) - C(2 * n, n - 1) + p) % p;
}
};

浙公网安备 33010602011771号