Catalan数

article/2025/11/7 10:07:10

Catalan(卡特兰)数

卡特兰数,又称卡塔兰数,是组合数学中一种常出现于各种计数问题中的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名。1730年左右被蒙古族数学家明安图 (1692-1763)使用于对三角函数幂级数的推导而首次发现,1774年被发表在《割圜密率捷法》。
——百度百科

基本概念

引入

首先我们想这么一个问题:

对于一个 n × n n \times n n×n的一个矩形方格,连接其副对角线。

一个 B u g Bug Bug(虫子)现在处在左下角,每次只能向上或向右移动一格,且不能越过蓝线,问有多少种不同的路径?

网格

首先如果不考了蓝线,根据曼哈顿距离原理可知,任意一个路径都可写成是一个只有“上”和“右”的序列,例如:上上右上右…。其长度为 2 n 2n 2n,分别有 n n n个上和 n n n个右,所以总的方案数为 C 2 n n C_{2n}^{n} C2nn,即在 2 n 2n 2n个位置上选 n n n个位置放上或右。

然后,对于每一个不符合要求的路径(绿线),其必定会有一个点与直线 y = x + 1 y=x+1 y=x+1相交(橙线),如上图的点 P P P,我们把直线 y = P y y=P_{y} y=Py以上的部分做关于直线 y = x + 1 y=x+1 y=x+1的对称(蓝色虚线),这时候的终点变成了 ( n − 1 , n + 1 ) (n-1,n+1) (n1,n+1),即对于问题从 ( 0 , 0 ) (0,0) (0,0)点到 ( n − 1 , n + 1 ) (n-1,n+1) (n1,n+1)点只能向右走或向上走的路径数,答案是 C 2 n n + 1 C_{2n}^{n+1} C2nn+1 C 2 n n − 1 C_{2n}^{n-1} C2nn1

最终我们得到答案是:

C 2 n n − C 2 n n + 1 C_{2n}^{n} - C_{2n}^{n+1} C2nnC2nn+1

也可以写成是:

C 2 n n − C 2 n n − 1 C_{2n}^{n} - C_{2n}^{n-1} C2nnC2nn1

因为 C 2 n n + 1 = C 2 n n − 1 C_{2n}^{n+1} = C_{2n}^{n-1} C2nn+1=C2nn1

Catalan的通项公式

这就是 C a t a l a n Catalan Catalan数列的原始定义。即:

C ( n ) = C 2 n n − C 2 n n + 1 C(n) = C_{2n}^{n} - C_{2n}^{n+1} C(n)=C2nnC2nn+1

对组合数进行化简(不要被算式吓到,就是一个通分化简的过程):

C ( n ) = C 2 n n − C 2 n n + 1 = ( 2 n ) ! n ! n ! − ( 2 n ) ! ( n + 1 ) ! ( n − 1 ) ! = 1 n + 1 ( ( 2 n ) ! ( n + 1 ) n ! n ! − ( 2 n ) ! n ! ( n − 1 ) ! ) = 1 n + 1 ( ( 2 n ) ! ( n + 1 ) n ! n ! − ( 2 n ) ! n n ! n ! ) = 1 n + 1 ( ( 2 n ) ! ( n + 1 ) − ( 2 n ) ! n n ! n ! ) = 1 n + 1 ( ( 2 n ) ! n ! n ! ) = 1 n + 1 C 2 n n C(n) = C_{2n}^{n} - C_{2n}^{n+1} \\ = \frac{(2n)!}{n!n!} - \frac{(2n)!}{(n+1)!(n-1)!} \\ = \frac{1}{n+1}( \frac{(2n)!(n+1)}{n!n!} - \frac{(2n)!}{n!(n-1)!} ) \\ = \frac{1}{n+1}( \frac{(2n)!(n+1)}{n!n!} - \frac{(2n)!n}{n!n!} ) \\ = \frac{1}{n+1}( \frac{(2n)!(n+1) - (2n)!n}{n!n!} ) \\ = \frac{1}{n+1}( \frac{(2n)!}{n!n!} ) \\ = \frac{1}{n+1}C_{2n}^{n} \\ C(n)=C2nnC2nn+1=n!n!(2n)!(n+1)!(n1)!(2n)!=n+11(n!n!(2n)!(n+1)n!(n1)!(2n)!)=n+11(n!n!(2n)!(n+1)n!n!(2n)!n)=n+11(n!n!(2n)!(n+1)(2n)!n)=n+11(n!n!(2n)!)=n+11C2nn

因此我们有 C a t a l a n Catalan Catalan数列的通项公式

C ( n ) = 1 n + 1 C 2 n n C(n) = \frac{1}{n+1}C_{2n}^{n} C(n)=n+11C2nn

解释:

  • 为了构造 n n n对合法的括号序列,我们先通过 ( 2 n n ) \binom{2n}{n} (n2n)种方法去填充"(“或者”)",然后再减去不符合条件的情况。每一种不符合条件的情况,都有存在一个最短前缀,使得右括号的数量=左括号的数量+1,我们这个前缀的每一个括号,那么就会得到一个左括号数量=右括号数量+1的括号序列且唯一对应,方案数为 ( 2 n n + 1 ) \binom{2n}{n+1} (n+12n),即为 ( 2 n n ) − ( 2 n n + 1 ) = 1 n + 1 ( 2 n n ) \binom{2n}{n} -\binom{2n}{n + 1} = \frac{1}{n+1}\binom{2n}{n} (n2n)(n+12n)=n+11(n2n)

Catalan的递推公式

构造递推公式要把 C ( n ) C(n) C(n) C ( n − 1 ) C(n-1) C(n1)联系起来,因此:

C ( n ) = 1 n + 1 C 2 n n C ( n − 1 ) = 1 n C 2 n − 2 n − 1 C(n) = \frac{1}{n+1}C_{2n}^{n} \\ C(n-1) = \frac{1}{n}C_{2n - 2}^{n-1} C(n)=n+11C2nnC(n1)=n1C2n2n1

打开:

C ( n ) = 1 n + 1 ( ( 2 n ) ! n ! n ! ) C ( n − 1 ) = 1 n ( ( 2 n − 2 ) ! ( n − 1 ) ! ( n − 1 ) ! ) C(n) = \frac{1}{n+1} ( \frac{(2n)!}{n!n!} )\\ C(n-1) = \frac{1}{n}( \frac{(2n-2)!}{(n-1)!(n-1)!} ) C(n)=n+11(n!n!(2n)!)C(n1)=n1((n1)!(n1)!(2n2)!)

所以:

C ( n ) = 4 n − 2 n + 1 C ( n − 1 ) C(n) = \frac{4n-2}{n+1} C(n-1) C(n)=n+14n2C(n1)

Catalan的计数公式

C ( n ) = ∑ i = 0 n − 1 C ( i ) ⋅ C ( n − 1 − i ) C(n) = \sum_{i=0}^{n-1}C(i) \cdot C(n-1-i) C(n)=i=0n1C(i)C(n1i)

解释:

  • 为了构造 n n n对合法括号序列,其序列第一项一定是"(",那么我们枚举第一项"(“对应的”)“的位置,在第一对”()“中有 i i i对合法的序列,在第一对”()"外有 n − i − 1 n-i-1 ni1对合法的序列,我们枚举 i i i 0 0 0 n − 1 n-1 n1,求和累加得到上述式子。
  • 考虑 n n n个元素的出入栈次序问题,第一个入栈的元素可以在第 1 , 2 , 3 , 4 , … , n − 1 1,2,3,4,\ldots,n-1 1,2,3,4,,n1处出栈,那么我们枚举其前后的元素个数递归即可。

上述是 C a t a l a n Catalan Catalan数列的常用几个公式,下面给出 C a t a l a n Catalan Catalan数列前 10 10 10项,接下来讲解实际的问题。

C ( 0 ) = 1 C ( 1 ) = 1 C ( 2 ) = 2 C ( 3 ) = 5 C ( 4 ) = 14 C ( 5 ) = 42 C ( 6 ) = 132 C ( 7 ) = 429 C ( 8 ) = 1430 C ( 9 ) = 4862 C ( 10 ) = 16796 C(0)=1 \\ C(1)=1 \\ C(2)=2 \\ C(3)=5 \\ C(4)=14 \\ C(5)=42 \\ C(6)=132 \\ C(7)=429 \\ C(8)=1430 \\ C(9)=4862 \\ C(10)=16796 C(0)=1C(1)=1C(2)=2C(3)=5C(4)=14C(5)=42C(6)=132C(7)=429C(8)=1430C(9)=4862C(10)=16796

实际问题

出栈次序问题

P1044

对于一个序列,栈的大小大于序列的大小,问不同的出栈序列有几个?

例如序列: 123456 123456 123456。设序列长度为 n n n的答案数为 C ( n ) C(n) C(n)

  1. 首先栈里面没有元素,我们只能把 6 6 6入栈。
  2. 接下来我们不管栈顶元素 6 6 6,把栈看成是一个空栈,面对序列 12345 12345 12345,又是一个子问题。
  3. 在我们处理子问题的时候,我们考虑 6 6 6什么时候出栈?
  4. 元素 6 6 6可以在 12345 12345 12345都处理完毕之后出栈,此时的数量为 C ( 5 ) C(5) C(5);也可以在 1 1 1 2345 2345 2345之间出栈,此时的数量为 C ( 1 ) × C ( 4 ) C(1) \times C(4) C(1)×C(4);同理,剩下的数量分别为 C ( 2 ) × C ( 3 ) C(2) \times C(3) C(2)×C(3) C ( 3 ) × C ( 2 ) C(3) \times C(2) C(3)×C(2) C ( 4 ) × C ( 1 ) C(4) \times C(1) C(4)×C(1) C ( 5 ) C(5) C(5)
  5. 把这些不同情况的数量进行加和,可以发现 C ( n ) C(n) C(n)就是 C a t a l a n Catalan Catalan数列,我们推导的方法就是 C a t a l a n Catalan Catalan数列的计数公式。
int dp[19];int main()
{int n;cin >> n;dp[0] = dp[1] = 1;for(int i = 2;i<=n;i++){for(int k = 0;k<=i-1;k++){dp[i] += dp[k] * dp[i-1-k];}}cout << dp[i];return 0;
}

n个节点的不同形态的二叉树的数量

n n n个节点的不同形态的二叉树的数量是多少呢?设答案为 C ( n ) C(n) C(n)

选定根节点之后,还剩 n − 1 n-1 n1个节点可以放置,只考虑左子树,左子树可以有 0 0 0 1 1 1一直到 n − 1 n-1 n1个节点,右子树用 n − 1 n-1 n1减去左子树的节点数即可。因此可以得到公式:

C ( n ) = ∑ i = 0 n − 1 C ( i ) ⋅ C ( n − 1 − i ) C(n) = \sum_{i=0}^{n-1}C(i) \cdot C(n-1-i) C(n)=i=0n1C(i)C(n1i)

发现 C ( n ) C(n) C(n)就是 C a t a l a n Catalan Catalan数列。

同理LeetCode 96 不同的二叉搜索树。

考虑 1 , 2 , 3 , 4 , … , n 1,2,3,4,\ldots,n 1,2,3,4,,n分别当根节点的情况,其答案还是 C a t a l a n Catalan Catalan数列。

n个节点的不同形态的树的数量

我们根据树与二叉树“左儿子右兄弟”的对应法则,每一种 n n n个节点形态的树,都对应一种 n − 1 n-1 n1个节点的二叉树的形态,因此答案为 C n − 1 C_{n-1} Cn1

从左下角走到右上角不穿过副对角线的方案数

即开篇的问题,可以理解为向左走就是入栈,向上走就是出栈,等价与出栈次序问题。这也给定了出栈次序问题的一个几何解释,连接了计数公式和通项公式的桥梁。

合理的括号序列问题

给定 n n n个括号"()",问有几种合理的括号序列问题。例如 n = 2 n=2 n=2的时候,"(())“和”()()“就是合法的,像”))(("就是不合法的。同理与出栈次序问题,添加一个左括号相当于入栈,添加一个右括号相当于出栈。

凸n边形的三角形划分方案数

我们知道,给定一个凸n边形,可以用 n − 3 n-3 n3条线段把这个多边形划分成 n − 2 n-2 n2个三角形,其中线段的顶点是多边形的顶点,线段不能交叉。

我们任意选取一个顶点设为 1 1 1,然后按照顺时针或者逆时针的顺序给顶点编号,与 1 1 1相邻的顶点是 n n n 2 2 2,选取 1 1 1 n n n剩下的顶点为 2 , 3 , … , n − 1 2,3,\ldots,n-1 2,3,,n1,在剩下的顶点中选取一个顶点当做是 k k k,那么令 1 → k → 1 1 \to k \to 1 1k1的区域为 A A A i , k , n i,k,n i,k,n这是个三角形, k → n → k k \to n \to k knk这个区域为区域 B B B,那么分别把区域 A A A,和 B B B看成是子问题,发现仍然是 C a t a l a n Catalan Catalan数列。

例题

P2532

普通卡特兰计数,需要高精度。

总结

基本关于 C a t a l a n Catalan Catalan数列的相关问题就这些了,我们发现,基本大多数问题都可以转换成出栈次序问题,所以我们掌握了出栈次序问题的思考方式,我们也就掌握了 C a t a l a n Catalan Catalan数列相关计数问题的思考方式。


http://chatgpt.dhexx.cn/article/SKbFwmvd.shtml

相关文章

服务端程序的keeplive

查看更多 https://www.yuque.com/docs/share/045e7b34-8b67-408f-bdac-11a2e8645342

LVS和Keeplive

文章目录 一、Keepalived 概述1. 为什么需要 keepalived2. keepalived 是什么3. keepalived 服务重要功能4. keepalived 高可用故障切换转移原理5. keepalived 体系主要模块及其作用6. 使用 keepalived 实现双机热备 二、LVS DR Keepalived 高可用集群构建1. 集群概述3. 案例…

RabbitMQ-KeepLive

文章目录 1. KeepLive基础知识2. KeepLive安装3. KeepLive主节点配置4. KeepLive从节点配置5. 执行脚本 1. KeepLive基础知识 基础概述 三大特性 高可用原理 2. KeepLive安装 3. KeepLive主节点配置 4. KeepLive从节点配置 5. 执行脚本 VIP的漂移&#xff1a;使用了同一…

list列表跳转保存位置,返回列表刷新keeplive

vue页面路由跳转离开时保存滚动条位置&#xff0c;进入该页面是获取位置 beforeRouteLeave (to, from, next) {const position document.documentElement.scrollTopsessionStorage.setItem(scrollTop, JSON.stringify(position))next()},// // 进入该页面时&#xff0c;用之…

keeplive+haproxy+nginx

Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器&#xff0c;也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的&#xff0c;第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证…

keeplive发生脑裂问题处理过程

某上云项目中,k8s管理节点vip突然时不时无法访问了&#xff0c;针对这个问题&#xff0c;首先对vip发起了一个长ping;发现过一会就ping不通了&#xff0c;结果如下&#xff1a; 然后查看keeplive的日志&#xff0c;两台主机会发生vip会时不时的争抢&#xff1a; 因为我们在这两…

vue单页面html缓存问题,vue单页面 回退页面 keeplive 缓存问题

场景&#xff1a;项目中遇到 vue 点击回退 从A页跳到B页&#xff0c;缓存A页&#xff0c;当B页状态修改再次返回A时&#xff0c;A页查询条件缓存不刷新&#xff0c;列表刷新 A页&#xff1a; B页&#xff1a; html 解决方法&#xff1a; 利用keep-alive 缓存须要缓存的页面 1.…

Vue生命周期和钩子函数及使用keeplive缓存页面不重新加载

Vue生命周期 每个Vue实例在被创建之前都要经过一系列的初始化过程&#xff0c;这个过程就是vue的生命周期&#xff0c;在这个过程中会有一些钩子函数会得到回调 Vue中能够被网页直接使用的最小单位就是组件&#xff0c;我们经常写的&#xff1a; var vm new Vue({el: #app,...…

LVS(三)lvs+keeplive

一 场景引入1 我们知道LVS仅仅是做根据调度算法和策略来做负载均衡的&#xff0c;LVS本身只是调度后端服务器&#xff0c;并不管后端服务器的死活&#xff0c;想想这样一个场景&#xff1a;如果由于由于某种原因&#xff0c;后端服务器挂掉&#xff0c;而调度服务器却不知道&am…

lvs+keeplive

Keepalived概述 调度出现单点故障&#xff0c;如何解决&#xff1f;Keepalived实现了高可用集群Keeepalived最初是为LVS设计的&#xff0c;专门监控各服务器节点状态Keepalived后来加入了VRRP功能&#xff0c;防止单点故障 Keepalived运行原理 Keepalived检测每个服务器节点…

使用keeplive处理socket网络异常断开

网络异常断开原因主要有那些呢&#xff1f;归纳起来主要有以下两种&#xff1a; 1、客户端程序异常。 对于这种情况&#xff0c;我们很好处理&#xff0c;因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常&#xff08;就是WinSock2中的10054异常&#xff09;。…

mysql mm keeplive_mysql +keeplive

下载tar包 ./configure --prefix/usr/local/keepalived --with-kernel-dir/usr/src/kernels/2.6.32-431.el6.x86_64/ \ 注意加内核 &&make && make install cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/ cp /usr/local/keepalived…

解决keep-live使用之后的问题

keep-aliv能够帮助我们实现页面ajax请求只被请求一次&#xff0c;在你跳转页面的时候&#xff0c;也不会被请求多次&#xff0c;可是比如在旅游页面中&#xff0c;当我们在城市选择页面重新选择城市&#xff0c;这个时候就需要重新发送一个ajax请求&#xff0c;来显示对应城市的…

nginx和keeplive实现负载均衡高可用

一、 Keeplive服务介绍 Keeplive期初是专门为LVS设计的&#xff0c;专门用来监控LVS集群系统中各个服务节点的状态&#xff0c;后来又加入VRRP的功能&#xff0c;因此除了配合LVS服务以外&#xff0c;也可以作为其他服务&#xff08;nginx&#xff0c;haroxy&#xff09;的高可…

php用Ajax传递数组

代码如下: 定义array数组 var array [1,2,3];$.ajax({url:"cart.php?actdelcart",async:false,type:POST,data:{array:array},dataType:json,traditional: true,success:function(data){alert(data)},error:function(){alert("#");}}); 当我们用ajax传递…

【JQuery】Ajax 参数为数组 的方法

背景介绍 前端页面为HTML&#xff0c; 后端为Spring html中根据多选框的值&#xff0c;使用ajax请求接口动态加载其他元素的选项值。 代码 // select 下拉多选框的值var idCardType $("#idCardType").val();// [2075, 2077, 2078]$.ajax({url : url,type : "…

使用ajax传递数组和后台接收

使用ajax异步的提交多选框得到需要操作的对象的id&#xff0c;这时我们可以把每一个id做出一个对象&#xff0c;之后放到一个数组中&#xff0c;再使用JSON.stringify()对这个数组进行json的格式化&#xff1b;在后台中再inputStream中解析出我们的json字符串&#xff0c;之后只…

ajax传数组,后端接收数组

ajax内容 使用JSON.stringify(&#xff09;将数组转换为JSON字符串 //发送ajax将数组发送给handler$.ajax({url:"admin/batch/remove.json", //服务器接收请求的URL地址type:"post", //设置请求方式postcontentType:"application/json;charsetUTF-8&…

教你怎么用ajax传数组(也可以是转为json)

我之前写过一个关于ajax的详解&#xff0c;那个是标准的ajax&#xff0c;今天介绍的是怎么用ajax传递数组这样的数据类型呢&#xff1f;很多的时候我们需要给后端的数据不是几个单独的数据&#xff0c;一般见到的代码的是这样的&#xff1a; data: { id : id, name : name, se…

Ajax传递数组到后台的两种方式

直接传输不可行 第一种 将ajax参数传递修改为tradition: traditional: true $.ajax({xhrFields: {withCredentials: true},async: true,url: basePath "/consumer/work",type: "post",dataType: "json",traditional: true,data : {sql :text,/…