卡特兰数
来源:互联网 发布:淘宝清除缓存 编辑:程序博客网 时间:2024/04/28 10:02
前言:
今天发现了一道题,认认真真的以为是组合数,认认真真的看了半天,认认真真的懵逼了好久,最后去看了题解,原来这个玩意儿是卡特兰数······
内容:
卡特兰数的数值h(n)为1 ~ n这n个数,按照从小到大的顺序入栈,不同的出栈序列种数。
公式:
1、h(i) = c(2n, n) - c(2n, n - 1)
证明:我们来形象一点考虑这个序列的意义,我们把入栈看做I,出栈看做O,那么相当于我们现在有一个长度为2 * n的IO序列,并且对于这个序列的每一个前缀都应该满足I的个数大于O的个数,(入栈数大于等于出栈数),那么首先,我们先不考虑后一个前缀中的个数限制,那么总的I有n个,O有n个的情况一定是C(2n,n)个,然后考虑,非法的情况,首先我们还是保证这个非法的序列有n个I,n个O,那么显然的,因为它是非法的,那么一定存在某个位置x,满足x是一个奇数,并且是第一个满足序列1 ~ x中的O的个数比I的个数大1的位置,那么考虑这种情况意味着什么,如果,我们将1 ~ x中的I全部变成O,O全部变成I,那么原来的序列,会变成一个有着n +1个I,有n - 1个O的序列,并且显然,任意不同的非法序列,都一定能对应不同的有着n - 1个O,n + 1个I的序列,我们在来反向考虑,这样的序列是不是也一定能够对应一个非法序列,显然对于一个满足有n - 1个O,n + 1个I的序列,我们一定能找到一个位置x,满足x为奇数,并且,x是第一个满足1 ~ x中,I的数量比O的数量多1的(显然I的总数大于O的总数),那么我们将这一段中的I和O反转,就形成了一个有着n个O,n个I的非法序列,所以说最终的合法的序列种数为C(2n,n) - C(2n, n - 1)个,得证。
2、
证明:我们还是在定义的基础上来搞一搞,设我们最后出栈的数为k,那么k -1一定在k入栈之前就已经出栈,也就是说k入栈的时候,栈为空,那么1 ~ k- 1出栈序列有h(k- 1)中,同样的,因为,k为最后出栈的,所以在k入栈之后,k + 1 ~ n全部入栈并且出栈之后,k最后出栈,那么k +1 ~ n的出栈序列有h(n- k)种,那么我们枚举k就可以获得上面的表达式了。
3、h(n) = c(2n, n) / (n + 1)
证明:我们知道,c(2n,n) * n / (n + 1) = c(2n, n - 1),那么显然,从递推式一可以得到,h(n) = c(2n, n) - c(2n, n) * n / (n + 1) = c(2n, n) / (n + 1)
4、h(n) = h(n - 1) * (4 * n - 2) / (n + 1)
证明:比较形象的证明我是没有找到的,但是可以直接粗暴的从式子1恒等证明回来,所以姑且算作是纯数学推导吧,具体的只需要证明c(2n - 2, n - 1) * (4 * n - 2) = c(2n, n)就可以了。
例题:有趣的数列
题目背景:
bzoj1485
分析:卡特兰数 + 取膜
一共2 * n个数,n个奇数项,n个偶数项,一个长度为2 * n,1 ~ 2 * n的序列,每一个前缀中的奇数项一定大于等于偶数项,那么也就是可以想成是n个数进栈,求出栈序列,也就是卡特兰数了,然后我们要求的就是c(2n, n) - c(2n, n - 1)直接暴力分解质因数就可以了,复杂度O(nlogn)。
Source:
/*created by scarlyw*/#include <cstdio>#include <string>#include <algorithm>#include <cstring>#include <iostream>#include <cmath>#include <cctype>#include <vector>#include <set>#include <queue>const int MAXN = 1000000 + 10;int n, mod, prime_cnt;int up[MAXN], down[MAXN], prime[MAXN];bool not_prime[MAXN];inline void seive(int n) {not_prime[1] = true;for (int i = 2; i <= n; ++i) {if (!not_prime[i]) prime[++prime_cnt] = i;for (int j = 1; j <= prime_cnt && prime[j] * i <= n; ++j) {not_prime[i * prime[j]] = true;if (i % prime[j] == 0) break;}}}inline int solve(int n, int m) {static int cnt[MAXN];for (int i = 1; i <= m; ++i) down[i] = i, up[i] = n - i + 1;for (int i = 1; i <= prime_cnt; ++i) {int x = prime[i];for (int j = x; j <= m; j += x)while (down[j] % x == 0) cnt[x]++, down[j] /= x;for (int j = n % x + 1; cnt[x]; j += x) while (up[j] % x == 0 && cnt[x]) cnt[x]--, up[j] /= x;}int ans = 1;for (int i = 1; i <= m; ++i) ans = (long long)ans * (long long)up[i] % mod;return ans;}int main() {scanf("%d%d", &n, &mod), seive(n);printf("%d", (solve(2 * n, n) - solve(2 * n, n - 1) + mod) % mod);return 0;}
- 卡特兰数,高精度卡特兰数
- 卡特兰数
- 卡特兰数(Catalan)
- 卡特兰数
- 卡特兰数
- 卡特兰数 大数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 卡特兰数
- 对于GLSL,随机/杂点函数
- 连接的管道-HDU
- scanf函数的返回值
- nginx 调试指南资源收集
- 科普:维基百科与其创始人
- 卡特兰数
- 用图片隐藏信息
- Uncaught Exception java.lang.NoSuchMethodError: org.apache.jmeter.samplers.SampleSaveConfiguration.s
- 透视变换——鸟瞰图
- JavaScript学习资料三
- PHP获取变量的类型(gettype和settype)及类型判断
- 字符串函数---atof()函数详解及实现
- Windows7以上使用WFP驱动框架实现IP数据包截取(二)
- 廖大JS map