卡特兰数和超级卡特兰数

卡特兰数和超级卡特兰数



这篇博客主要是想讲一下超级卡特兰数(大施罗德数),顺带就想讲一下卡特兰数.

卡特兰数

定义

卡特兰数记为\(C_n\)
\(C_1=1\)
\(\forall n \geq 2, C_n=\sum_{i=1}^{n-1}C_i C_{n-i}\)

前几项大概是: 1, 1, 2, 5, 14, 42, 132......

直接递推未免效率太低,我们考虑用生成函数优化.
显然有\(C(x)=C(x)^2+x\)
解得\(C(x)={1-(1-4x)^{\frac 1 2}\over 2}\)
将\((1-4x)^{\frac 1 2}\)用广义二项式定理展开
得到\(C(x)\)中\(x^n\)项系数为\(\frac 1 n \binom {2n-2}{n-1}\)

组合意义

1.\(n+1\)边形的三角剖分方案数.
注意到任意三角形一定是某一条边在多边形上,然后再选一个不是这条边的端点的点,而且注意到这样一个三角形不会被计算两次,所以会得到一个类似于卡特兰数的递推式.
如果直接枚举一条边然后分成两边的话,是算不对的,因为可能一个点不与多边形上任意非相邻点连边.如果要强行这么算的话,那就得枚举所有的边然后除以算重的次数.

2.\(n\)个数的连乘积,只用结合律(加括号)来改变乘法顺序,问有多少中乘法的顺序.
考虑枚举最后是哪两个数相乘,不难发现是卡特兰数的形式.

3.\(n-1\)对括号的括号序列的合法方案数.
枚举第一个左括号所对应的右括号的位置即可.

4.从(0,0)到(n-1,n-1),每次只能往右或往上走,求不超过\(y=x\)这条直线的方案数.
考虑第一步肯定是往右边走,然后枚举第一个经过\(y=x\)这条直线的位置.
另外一种思路,将条件变成不经过\(y=x+1\)这条直线,那么寻找(0,0)关于\(y=x+1\)的对称点
(-1,1),显然每一条从(0,0)到(n-1,n-1)的不合法路径对应一条从(-1,1)到(n-1,n-1)的不合法路径.

超级卡特兰数

记超级卡特兰数为\(S_i\)
有\(S_1=1\)
\(\forall i \geq 2,S_i=S_{i-1}+\sum_{i=1}^{n-1}S_iS_{n-i}\)

写成生成函数的形式是\(S(x)=xS(x)+S(x)^2+x\)
解得\(S(x)={1-x - \sqrt{x^2-6x+1} \over 2}\)

如果还是用广义二项式定理展开的话,经过复杂化简,可以得到\(S_n=\sum_{i=1}^n \binom {n+i-1} {2i}C_i\),后面我们可以看见,这个式子有着清晰的组合意义.

不过网上还有一种\(O(n)\)递推的方法,简而言之就是快速求出\(\sqrt{x^2-6x+1}\)

接下来给出的一种方法,可以在\(O(nk)\)的复杂度快速求出k次多项式开方后前n项的值
设要开方的多项式为\(P(x)\),开方后的多项式为\(F(x)\).
有\(F(x)=P(x)^{\frac 1 2}=\sum_{i=0}^{\infty} f_i x^i\)
两边求导,可得\(F'(x)=P(x)^{-\frac 12} P'(x)\)
有\(F(x)P'(x)=F'(x)P(x)\)
对比每一项系数,不难得到k+1项的递推式.

最后给出递推公式:\((n+1)f_{n+1}=(6n-3)f_n-(n-2)f_{n-1}\),不过要注意这个递推公式除了第一项其他的项都是超级卡特兰数的\(\frac12\)

组合意义

相比卡特兰数,超级卡特兰数的唯一区别就是在递推的时候加了一个\(S_{n-1}\),那么其组合意义也可以看做是卡特兰数的扩展.

1.\(n+1\)边形的任意剖分方案数.
还是考虑枚举一条多边形上的边,那么有可能这条边仍然与另一个点拉成一个三角形,也有可能这条边上没有,那么把这两种加起来就是定义的递推式

2.括号序列,每个位置可能左括号,右括号和0.括号对数与0的个数之和为n-1, 问合法的括号序列数.
同样枚举第一个是左括号还是0.
值得一提的是,可以看成先插括号再插0,那么枚举括号对数i,0有n-i-1个,需要放入2i+1个位置中,那么不难得到上面通过广义二项式推出来的式子.

3.从(0,0)到(n-1,n-1),每次能往右,往上,往右上走,求不超过\(y=x\)这条直线的方案数.
枚举第一次是走右上还是走右.
同样使用容斥思想,把答案转化为从(0,0)到(n-1,n-1)减去(-1,1)到(n-1,n-1).
那么从(0,0)到(n,m)的路径条数怎么求呢.可以考虑枚举往右上的次数,然后还是考虑先走右和上,然后再把走右上的插入即可.

原文地址:https://www.cnblogs.com/gzy-cjoier/p/10394016.html

时间: 2024-08-29 15:48:42

卡特兰数和超级卡特兰数的相关文章

java算法之超级丑数

问题描述: 写一个程序来找第 n 个超级丑数. 超级丑数的定义是正整数并且所有的质数因子都在所给定的一个大小为 k 的质数集合内. 比如给你 4 个质数的集合 [2, 7, 13, 19], 那么 [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] 是前 12 个超级丑数. 注意事项 1:永远都是超级丑数不管给的质数集合是什么. 2:给你的质数集合已经按照升序排列. 0 < k ≤ 100, 0 < n ≤ 10^6, 0 < primes[i] &l

卡特兰数,高精度卡特兰数

简介:卡特兰数是组合数学中经常出现的一个数列. 个人觉得无论是递推公式还是代表的含义都比斐波那契数列难理解一些. 递推公式: 应用: 1.Cn表示长度2n的dyck word的个数.Dyck word是一个有n个X和n个Y组成的字串,且所有的前缀字串皆满足X的个数大于等于Y的个数.以下为长度为6的dyck words XXXYYY XYXXYY XYXYXY XXYYXY XXYXYY 分析:对于n个X,n个Y的排列来说一共有C(n,2n)种,还要排除其中不符合要求的排列.不符合条件的排列对于某

【贪心】超级波浪数- 10045

[贪心]超级波浪数- 10045 Time Limit: 1000MS Memory Limit: 32768KB 波 浪数,数的大小关系就象波浪,如“14352”我们从左向右看时数的大小由小到大,然后到小,再到大,再到小,当然14253.14352.24153. 24351.34152.34251.212.121也是波浪数,但122不是波浪数,112,1221也不是波浪数,现在有一个很大的数,我们想从中选 一些数出来,组成一个波浪数,由于数很大,我们叫它超级波浪数.给定一个数,请从中选一个最长

超级丑数--用查找的api解决

class Ugly { constructor(n, primes) { this.n = n this.primes = primes } getAll() { // 超级丑数列表 let res = [1] let i = 2 let primes = this.primes // 不知道上限用while循环 while (res.length < this.n) { let arr = Ugly.getPrimies(i) let k = 0 let l = arr.length for

python 脚本(获取指定文件夹、指定文件格式、的代码行数、注释行数)

1.代码的运行结果: 获取 指定文件夹下.指定文件格式 文件的: 总代码行数.总注释行数(需指定注释格式).总空行数: 1 #coding: utf-8 2 import os, re 3 4 # 代码所在目录 5 FILE_PATH = './' 6 7 def analyze_code(codefilesource): 8 ''' 9 打开一个py文件,统计其中的代码行数,包括空行和注释 10 返回含该文件总行数,注释行数,空行数的列表 11 ''' 12 total_line = 0 13

Fibonacci数列是这样定义的: F[0] = 0 F[1] = 1 for each i ≥ 2: F[i] = F[i-1] + F[i-2] 因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, ...,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1

Fibonacci数列是这样定义的:F[0] = 0F[1] = 1for each i ≥ 2: F[i] = F[i-1] + F[i-2]因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, ...,在Fibonacci数列中的数我们称为Fibonacci数.给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数. 输入描述: 输入为一个正整数N(1 ≤ N

C++统计代码注释行数 &amp; 有效代码行数 &amp; 代码注释公共行 &amp; 函数个数

问题来源,在14年的暑假的一次小项目当中遇到了一个这样的问题,要求统计C++代码的注释行数,有效代码行数,代码注释公共行数,以及函数个数. 下面稍微解释一下问题, 1)注释行数:指有注释的行,包括有代码和注释的公共行(如:3,4,15,22...) 2)有效代码行:指有代码的行,包括有代码和注释的公共行(如:1,4,11,15,25....) 3)代码注释公共行:指又有代码又有注释的行(如:4,15...) 4)函数个数:这个不用说明了吧. 以下为注释情况展示代码: 1 #include <st

calculate the number of characters-统计文件中的字符数,非空白字符数,字母数,输入到文件和屏幕:

//calculate the number of characters-统计文件中的字符数,非空白字符数,字母数,输入到文件和屏幕: #include<iostream> #include<fstream> #include<cstdlib> #include<cmath> int main() { using namespace std; ifstream fin; ofstream fout; double ch1 = 0,ch2 = 0,letter

用JAVA写一个函数,功能如下: 任意给定一组数, 找出任意数相加之后的结果为35(任意设定)的情况

用JAVA写一个函数.功能如下:任意给定一组数,例如{12,60,-8,99,15,35,17,18},找出任意数相加之后的结果为35(任意设定)的情况. 可以递归算法来解: package test1; import java.util.Arrays; public class demo { public static void main(String[] args) { String str = "12,60,-8,99,15,35,17,18,8,10,11,12"; int s