[数论] 卡特兰数
LAST UPD:2023/09/10 更新了部分例题。
引入 · 基本模型
有 \(n\) 个元素进栈序列为 \(1,2,3,4\dots n\)。求有多少种出栈序列
我们需要确保最后一次操作后,栈中没有元素。因此,共有 \(2n\) 次操作。(每个元素进栈一次,出栈一次)
对于每次操作,如果我们想出栈,则它一定要有数字可以 pop。如果我们把栈抽象成一条链,若第 \(k\) 次想要出栈,则必须满足 \(sum_k \geq 0\)(\(sum_k\) 表示前 \(k\) 个操作的前缀和)
我们先不考虑不合法的序列,则共有 \(C_{n}^{2n}\) 种方案。也就是在 \(2n\) 次操作中选 \(n\) 个标记为 \(1\)。\(1,-1\) 一定是一一对应的。
对于不合法的序列呢?
举个例子:对于不合法序列 \(+1,-1,-1,+1,-1,+1\) , 显然从第 \(3\) 位就不合法。若对前 \(3\) 位进行取反,即序列变成 \(-1,+1,+1,+1,-1,+1\)。容易发现变成了 \(n+1\) 个 \(1\) 。
那么这个性质是否存在普遍性?
我们找的是第一个前缀和小于 \(0\) 的位置,因此它的前缀和一定是 \(-1\)。它前面的 \(-1\) 一定比 \(1\) 多一个。若取反,则 \(1\) 比 \(-1\) 多一个。就会导致 \(1\) 变成 \(n+1\) 个,\(-1\) 变成 \(n-1\) 个。
取反后的序列和取反前的序列一定是一一对应的。也就是从取反后的序列一定能变换成唯一的取反前的序列。
因此,不合法的序列个数等于 \(C_{n+1}^{2n}\)。 这里运用了转换法。因为取反前和取反后的序列一一对应,所以找取反后的序列个数即为不合法的方案个数。
所以,合法的出栈数量应为:
其中 \(\frac{C^{2n}_n}{n+1}\) 即为卡特兰数的通项公式。
定义
卡特兰数有多个定义方式,例如递归定义:
这个式子我们可以用凸多边形拆分三角形问题推导。下文也会提到。
递推关系
因此,只要我们发现题目中的数据具有以上任意一种关系,那么题目就迎刃而解,因为这就是卡特兰数列。
以及上文提到的通项公式:
直接阅读可能非常抽象,接下来我们给出几个卡特兰数的典型例题。事实上很多题目都是和上面的进出栈问题是一样的。
典例1:01序列
你有 \(n\) 个 \(0\) 和 \(n\) 个 \(1\)。请构造一个长度为 \(2n\) 的 \(01\) 序列,使得任意一个前缀中 \(1\) 的个数大于 \(0\) 的个数,求有多少种构造方式。
不妨把 \(0\) 看作类似于上述出栈问题的 \(-1\)。对于总共的方案数显然是 \(C^{2n}_n\) 。对于不合法的方案数,我们仍像上面引入的问题一样,找到第一个前缀和为 \(-1\) 的不合法位置,对它即它前面的每个数取反。因此不合法的方案数是 \(C^{2n}_{n+1}\)
总共的方案数即为 \(C^{2n}_n-C^{2n}_{n+1}\)
典例2:括号匹配
你有 \(n\) 个左括号,\(n\) 个右括号,请把它们配成合法的括号序列,求方案个数。
把左括号看作 \(-1\),右括号看作 \(+1\) 。然后就是和上面的思考方式一样了。
典例3:球迷购票问题
有 \(n\) 个人有 50 元的钱,\(n\) 个人有 \(100\) 元的钱,请求出有多少种合法排列,使得售票员不会找不出钱(售票员一开始没有钱)
把 \(50\) 元钱的人看作 \(+1\),\(100\) 元钱的看作 \(-1\)。然后就是卡特兰数。
由此可见,卡特兰数本质上就是将 不合法的方案映射。找到第一个不合法的位置,将其以及前面所有操作取反进行映射。
典例4:平面直角坐标系中的路径问题
在平面直角坐标系中,你将从 \((0,0)\) 走到 \((n,n)\)。你不得越过直线 \(y=x\)(可以走上去)。求有多少种不同的路径方案。
乍看是一个 dfs。如果看不出性质我们可以先打表处理,再观察性质。
先不考虑限制条件,则共有 \(C^{2n}_n\) 中方案。因为最后要走到 \((n,n)\)。所以一定是向上走 \(n\) 步,向右走 \(n\) 步的。
显然,直线 \(BC\) 为函数 \(y=x+1\)。因为不能越过 \(y=x\) 即不能碰到 \(y=x+1\)。
路径 \(DEFKHIJKLM\) 显然不是一个合法路径。它第一次碰到 \(y=x+1\) 的点为 \((2,3)\)。如果把它以及前面的操作全都取反,即向上变成向右,向右变成向上。则
可以发现终点变成 \((n,n-1)\)。向上走 \((n-1)\) 步,向右走 \((n+1)\) 步。
所以,答案就转换为 \(C^{2n}_n-C^{2n}_{n+1}\)
上述都是直接线性理解卡特兰数,接下来我们来看一下递归求卡特兰数的形式。
典例4:凸多边形划分三角形
在对角线不相交的情况下,将一个正多边形划分成若干个三角形,求划分方案数。
考虑动态规划。
容易证明,凸多边形的任意一条边最后一定被分在一个三角形中,因此我们可以先把这个三角形拿出来再考虑分解。
我们以正六边形举例,固定两个点 \(A,N\)。再在集合 \({A+1,N-1}\) 中任意选取一个点 \(k\)。连接 \(A,k,N\)。构造一个三角形。
我们这样的做法是先将这个三角形取出,再分别处理被三角形分成的两部分。
这个三角形将正六边形分为了两部分,分别是正 \(k\) 边形,正 \(n-k+1\) 边形。
对于选择的点 \(k\)。它的分割方案数为 \(f_k\times f_{n-k+1}\) 。
对于正 \(n\) 边形,显然分割方案数为:
显然对于点 \(A,N\) 任选两个相邻的点都不会影响答案。
这就是卡特兰数列的递归定义形式。用卡特兰数列的递推式求解即可。
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/17689682.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!