ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Catalan (卡特兰数)

2021-11-28 13:01:40  阅读:197  来源: 互联网

标签:lfloor ... frac int rfloor Catalan 2n 卡特兰


Catalan (卡特兰数)

前置知识:

1、排列数公式: A n m = n ( n − 1 ) ( n − 2 ) . . . ( n − m + 1 ) A^m_n=n(n-1)(n-2)...(n-m+1) Anm​=n(n−1)(n−2)...(n−m+1)​​

引入阶乘 n ! n! n!以后,排列数公式变形如下:

A n m = n ( n − 1 ) ( n − 2 ) . . . ( n − m + 1 ) = n ( n − 1 ) ( n − 2 ) . . . ( n − m + 1 ) ( n − m ) . . . 3 ∗ 2 ∗ 1 ( n − m ) . . . 3 ∗ 2 ∗ 1 = n ! ( n − m ) ! A^m_n=n(n-1)(n-2)...(n-m+1)=\frac{n(n-1)(n-2)...(n-m+1)(n-m)...3*2*1}{(n-m)...3*2*1}=\frac{n!}{(n-m)!} Anm​=n(n−1)(n−2)...(n−m+1)=(n−m)...3∗2∗1n(n−1)(n−2)...(n−m+1)(n−m)...3∗2∗1​=(n−m)!n!​

**注意:**为了保证公式在 n = m n=m n=m时成立,特规定 0 ! = 1 0!=1 0!=1

2、组合数公式: C n m = A n m A m m = n ( n − 1 ) ( n − 2 ) . . . ( n − m + 1 ) m ! = n ! m ! ( n − m ) ! C^m_n=\frac{A^m_n}{A^m_m}=\frac{n(n-1)(n-2)...(n-m+1)}{m!}=\frac{n!}{m!(n-m)!} Cnm​=Amm​Anm​​=m!n(n−1)(n−2)...(n−m+1)​=m!(n−m)!n!​​

其它性质:

C n m = C n n − m C^m_n=C^{n-m}_n Cnm​=Cnn−m​​​​​ (对称)

C n m = C n − 1 m + C n − 1 m − 1 C^m_n=C^m_{n-1}+C^{m-1}_{n-1} Cnm​=Cn−1m​+Cn−1m−1​​

C n 0 + C n 1 + C n 2 + . . . + C n n = 2 n C^0_n+C^1_n+C^2_n+...+C^n_n=2^n Cn0​+Cn1​+Cn2​+...+Cnn​=2n

注意: C n 0 = 1 C^0_n=1 Cn0​=1


Catalan:

卡特兰数是组合数学中的一种著名数列,通常用如下通项式表示(为了不与组合数C 冲突,本文用 f f f​ 表示卡特兰数): f ( n ) = C 2 n n n + 1 f(n)=\frac{C^n_{2n}}{n+1} f(n)=n+1C2nn​​​​​

通项式变形: f ( n ) = C 2 n n − C 2 n n − 1 f(n)=C^n_{2n}-C^{n-1}_{2n} f(n)=C2nn​−C2nn−1​

卡特兰数递推式: f ( n ) = ∑ i = 0 n − 1 f ( i ) ∗ f ( n − i − 1 ) f(n)=\sum\limits^{n-1}_{i=0}f(i)*f(n-i-1) f(n)=i=0∑n−1​f(i)∗f(n−i−1)​

与卡特兰数相关的问题:

1、 1 , 2 , . . . , n 1,2,...,n 1,2,...,n经过一个栈,形成的合法出栈序列的数量为 c a t n cat_n catn​

2、 n n n个左括号和 n n n个右括号组成的合法括号序列的数量为 c a t n cat_n catn​

3、 n n n个结点构成的不同二叉树的数量为 c a t n cat_n catn​

4、买票排队问题,票价为 x x x元,现在有 n n n个顾客用面值为 x x x的钱币购买,还有 n n n个顾客用面值为 x ∗ 2 x*2 x∗2的钱币购买,商家起初没有钱找零。此时形成的合法排队(商家可以给所有该找零的顾客找零)方案数量为 c a t n cat_n catn​

5、 n n n边形 ( n > = 3 ) (n>=3) (n>=3)切割 n − 3 n-3 n−3刀,要求剩下的图形都为三角形,切割的方案数为 c a t n cat_n catn​

6、在平面直角坐标系上,每一步只能向上或向右走,从 ( 0 , 0 ) (0,0) (0,0)走到 ( n , n ) (n, n) (n,n)并且除了两个端点外不接触 y = x y=x y=x的路线数量为 2 c a t n − 1 2cat_{n-1} 2catn−1​

实际做Catalan数的题目时,数值会非常大,通常配合高精度运算,通过阶乘分解的方法可以省去除法运算,只用高精度乘法模拟即可

阶乘分解

Acwing197 阶乘分解

​ 给定整数 N ( 1 < = N < = 1 0 6 ) N(1<=N<=10^6) N(1<=N<=106),试把阶乘 N ! N! N!分解质因数,按照算数基本定理的形式输出分解结果中的 p i p_i pi​和 c i c_i ci​即可( p i p_i pi​代表第 i i i个质因子, c i c_i ci​代表第 i i i个因子的个数)

​ 若 1 ∼ N 1\thicksim N 1∼N每个数分别分解质因数,再把结果合并,时间复杂度过高,为 O ( N N ) O(N\sqrt{N}) O(NN ​)。显然, N ! N! N!的每个质因子都不会超过 N N N,我们可以先筛选出 1 ∼ N 1\thicksim N 1∼N 的每个质数 p p p,然后考虑N!中一共包含多少个质因子 p p p​

​ N ! N! N!​中质因子 p p p​ 的个数就等于 1 ∼ N 1\thicksim N 1∼N​每个数包含质因子 p p p​ 的个数之和。在 1 ∼ N 1\thicksim N 1∼N​中, p p p​ 的倍数,即至少包含 1 1 1​ 个质因子 p p p​ 的显然有 ⌊ N p ⌋ \lfloor \frac{N}p \rfloor ⌊pN​⌋​个。而 p p p​ 的倍数,即至少包含 2 2 2​个质因子 p p p​ 的有 ⌊ N p 2 ⌋ \lfloor \frac{N}{p^2} \rfloor ⌊p2N​⌋​个。不过其中的 1 1 1​个质因子已经在 ⌊ N p ⌋ \lfloor \frac{N}p \rfloor ⌊pN​⌋​里统计过,所以只需要再统计第 2 2 2​个质因子,即累加上 ⌊ N p 2 ⌋ \lfloor \frac{N}{p^2} \rfloor ⌊p2N​⌋​,而不是 2 ∗ ⌊ N p 2 ⌋ 2 *\lfloor \frac{N}{p^2} \rfloor 2∗⌊p2N​⌋​。

​ 综上所述, N ! N! N!中质因子 p p p 的个数为:

⌊ N p ⌋ + ⌊ N p 2 ⌋ + ⌊ N p 3 ⌋ + . . . + ⌊ N p ⌊ l o g p N ⌋ ⌋ = ∑ p k ⩽ N ⌊ N p k ⌋ \lfloor \frac{N}p \rfloor+\lfloor \frac{N}{p^2} \rfloor+\lfloor \frac{N}{p^3} \rfloor+...+\lfloor \frac{N}{p^{\lfloor {log_pN} \rfloor}} \rfloor=\sum\limits _{p^k \leqslant N} \lfloor \frac{N}{p^k} \rfloor ⌊pN​⌋+⌊p2N​⌋+⌊p3N​⌋+...+⌊p⌊logp​N⌋N​⌋=pk⩽N∑​⌊pkN​⌋​​

​ 对于每个 p p p,只需要 O ( l o g N ) O(logN) O(logN)的时间计算上述和式。故对整个 N ! N! N!分解质因数的时间复杂度为 O ( N l o g N ) O(NlogN) O(NlogN)​

1、火车进出栈问题

Acwing130 火车进出栈问题

卡特兰数: f ( n ) = C 2 n n n + 1 f(n)=\frac{C^n_{2n}}{n+1} f(n)=n+1C2nn​​ , C 2 n n = ( 2 n ) ! n ! n ! C^n_{2n} = \frac{(2n)!}{n!n!} C2nn​=n!n!(2n)!​

把 ( 2 n ) ! (2n)! (2n)!的所有质因子 p i p_i pi​以及数量 c i c_i ci​​ 分别存放到两个数组中。用同样的方法计算出 n ! n ! n!n! n!n!并从这两个数组的对应位置减去对应数量。之后再分解 n + 1 n+1 n+1,也从这两个数组中减去对应数量。(结果为所有分母都被约分掉,相当于去掉了除法操作,证明略)

最后高精度乘法模拟两个数组运算即可

/*************************************************************************
        > File Name: 130.c
        > Author: Luzelin
        > Mail: 
        > Created Time: Sun Nov 28 10:59:19 2021
 ************************************************************************/

#include <stdio.h>

#define N 60000

int prime[N * 2 + 5], nums[N * 2 + 5], cnt;

//线性筛出小于等于n*2的所有质数
void Get_prime(int n) {
    for (int i = 2; i <= n; ++i) {
        if (prime[i] == 0)  prime[cnt++] = i;
        for (int j = 0; j < cnt && i * prime[j] <= n; ++j) {
            prime[i * prime[j]] = 1;
            if (i % prime[j] == 0)  break;
        }
    }
    return ;
}

//阶乘分解
//n!中存在质因子p的个数
int Get_div(int n, int p) {
    int cnt = 0;
    //除数乘p等价于被除数除p
    while (n > 1) {
        cnt += n / p;
        n /= p;
    }
    return cnt;
}

//高精乘模拟(压位优化,四位)
void mul(int *vec, int x) {
    int t = 0;
    for (int i = 1; i <= vec[0]; ++i) {
        vec[i] = vec[i] * x + t;
        t = vec[i] / 10000;
        vec[i] %= 10000;
    }
    while (t) {
        vec[++vec[0]] = t % 10000;
        t /= 10000;
    }
    return ;
}

int main() {
    int n;
    scanf("%d", &n);
    Get_prime(n * 2);
    //遍历所有可能是(n*2)!的质因子,如果存在把个数存放到相应位置。之后相对位置减去n!的质因子个数
    for (int i = 0; i < cnt; ++i) {
        int ind = prime[i];
        nums[ind] = Get_div(n * 2, ind) - Get_div(n, ind) * 2;
    }
    //减去n+1含有的因子
    int x = n + 1;
    for (int i = 0; x > 1; ++i) {
        while (x > 1 && x % prime[i] == 0) {
            --nums[prime[i]];
            x /= prime[i];
        }
    }
    int vec[1000000] = {1, 1};
    for (int i = 2; i <= 2 * n; ++i) {
        for (int j = 1; j <= nums[i]; ++j) {
            mul(vec, i);
        }
    }
    //第一位不需要补前导0
    printf("%d", vec[vec[0]]);
    for (int i = vec[0] - 1; i > 0; --i) {
        printf("%04d", vec[i]);
    }
    putchar('\n');
    return 0;
}

标签:lfloor,...,frac,int,rfloor,Catalan,2n,卡特兰
来源: https://blog.csdn.net/qq_40342400/article/details/121589792

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有