卡特兰数
卡特兰数是一个数列,其前几项为(从第零项开始) :
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, 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,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,…
满足递推式
C
n
+
1
=
C
0
C
n
+
C
1
C
n
−
1
+
.
.
.
+
C
n
C
0
(
n
−
3
)
C
n
=
n
2
(
C
3
C
n
−
1
+
C
4
C
n
−
2
+
.
.
.
+
C
n
−
1
C
3
)
\begin{aligned} &C_{n+1} = C_{0}C_{n}+C_{1}C_{n-1}+...+C_{n}C_{0}\\ &(n-3)C_n = \frac{n}{2} ( C_{3}C_{n-1}+C_{4}C_{n-2}+...+C_{n-1}C_{3})\\ \end{aligned}
Cn+1=C0Cn+C1Cn−1+...+CnC0(n−3)Cn=2n(C3Cn−1+C4Cn−2+...+Cn−1C3)
f
(
n
)
=
∑
i
=
0
n
−
1
f
(
i
)
∗
f
(
n
−
i
−
1
)
=
C
2
n
m
n
+
1
=
C
2
n
n
−
C
2
n
n
−
1
\begin{aligned} f(n) &= \sum_{i=0}^{n-1} f(i)*f(n-i-1) \\ & = \frac{C_{2n}^{m}}{n+1} \\ & = C_{2n}^{n}-C_{2n}^{n-1} \end{aligned}
f(n)=i=0∑n−1f(i)∗f(n−i−1)=n+1C2nm=C2nn−C2nn−1
通过状态转移方程简单理解一下卡特兰数:
f
[
i
]
[
j
]
=
f
[
i
]
[
j
−
1
]
+
f
[
i
−
1
]
[
j
]
f[i][j]=f[i][j-1]+f[i-1][j]
f[i][j]=f[i][j−1]+f[i−1][j]
输出递推矩阵。
其实每个数字就是上方和左方的数字加和,类似于杨辉三角。
杨辉三角是上方和左上方的数字加和。
ll f[N][N];
int main(){
scanf("%d",&n);
for(int i=0;i<=n;i++) f[0][i]=1;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
f[i][j]=f[i][j-1]+f[i-1][j];
printf("%lld",f[n][n]);
}
int solve1() {
f1[0] = f1[1] = 1;
cin >> n;
for(int i = 2; i <= n; i++)
for(int j = 0; j < i; j++)
f1[i] += (f1[j] * f1[i-j-1]); //f(n)=f(0)f(n-1)+f(1)f(n-2)+...+f(n-1)f(0)
printf("%lld\n",f1[n]);
return 0;
}
//公式2:
int solve2() {
f2[0] = f2[1] = 1;
cin >> n;
for(int i = 2; i <= n; i++)
f2[i] = f2[i - 1] * (4 * i - 2) / (i + 1); //f(n)=f(n-1)*(4*n-2)/(n+1)
printf("%lld\n", f2[n]);
return 0;
}
//公式3:
int solve3() {
cin >> n;
for(int i = 1; i <= 2 * n; i++) {
f[i][0] = f[i][i] = 1;
for(int j = 1; j < i; j++)
f[i][j] = f[i - 1][j] + f[i - 1][j - 1]; //f(n)=c(2n,n)/(n+1)
}
printf("%lld",f[2 * n][n] / (n + 1));
return 0;
}
应用
P1044 [NOIP2003 普及组] 栈
进出栈问题,问有多少种不同的生成序列的方式,手模一下发现满足卡特兰数
P1641 [SCOI2010]生成字符串
把 n 个 1 和 m 个 0 组成字符串,要求组成的字符串 任意的前 k 个字符中,1 的个数不能少于 0 的个数。求满足要求的字符串共有多少个。
有
C
2
n
n
C_{2n}^{n}
C2nn种情况,但是
C
2
n
n
−
1
C_{2n}^{n-1}
C2nn−1种不合法,满足卡特兰数的递推。
P1754 球迷购票问题
一个A买票后售票处会积累50元钱,一个B买票需要售票处找零50元钱。
说明在一个B买票前至少需要一个A买过票,那么我们就可以将A看作左括号,B看作右括号。
问题就是要求合法得括号匹配,即Catalan数