Catalan数与栈序列
之前的作业里有\([DH]\)里的一道题, 问:你有1个栈\(S\), 一个变量\(X\)可以用于存储; 现有:
\(read(X)\) (每次操作将\(1\)~\(N\)之间的整数按照从小到大顺序读入\(X\)中,每个数只\(read1\)次);
\(print(X)\);
\(push(X,S)\);
\(pop(X,S)\)四种操作.
求对于正整数\(N\),可以打印多少种\(1\)~\(N\)的全排列(原题问的是有多少种打不出来)?
\(Solution:\)
\(如下程序:\)
read(X);
push(X,S);
pop(X,S);
print(X,S);
与
read(X);
print(X,S);
打印效果相同(问题转化为\(N\)个元素进栈顺序已知,求出栈序列数).
因此考虑前\(N\)个正整数的进栈与出栈构成的\(01\)序列(规定入栈为0,出栈为1),与打印的排列可以建立一一映射,只需要计算\(nums\_of(0)=nums\_of(1)=N\)的栈序列数即可.
其中,因为\(pop\)空栈非法, 对于栈序列的任意前缀, 有\(nums\_of(0)\geqslant nums\_of(1)\).
答案是:\(\frac{\tbinom{2N}{N}}{N+1}\)
\(proof:\)
\(即为第N个Catalan数:C(N)=\frac{\tbinom{2N}{N}}{N+1}\)
还有一个递推公式:
分治:对一个合法序列:找到第一个\(nums\_of(0)=nums\_of(1)\)的前缀(一定存在),则它与后缀都是合法序列.
而对于第一个\(nums\_of(0)=nums\_of(1)\)的前缀,等价于\(0+{(规模-1)的合法序列}+1\),
因此,第一个长度为\(2n\)的\(nums\_of(0)=nums\_of(1)\)的前缀的个数\(=C(n-1)\)
可以用这个公式dp求第(前)\(N\)个\(Catalan\)数:
#include<cstdio>
#define LL long long
#define rep(i,a,b) for(int i=a;i<=b;++i)
LL C[114514] ;
int main() {
int N;
scanf("%d", &N);
C[0] = 1;
rep(i, 1, N) rep(j, 1, i)C[i] += C[j - 1] * C[i - j];
printf("%lld", C[N]);
}
这其实是2016年全国三卷理科数学选择题最后一个.