『筆記』數學數論(七)


\[\Huge{(七)組合數學之 \color{#3086B1}{卡特蘭數}} \]

簡介

卡特蘭數(Catalan),又稱明安圖數,是組合數學中一個常出現於各種計數問題的數列。

對應序列為:

\(1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, \cdots\)

滿足

\[M_{n+1} = M_0M_n + M_1M_{n-1} + \cdots + M_nM_0 \]

其中 \(C_0=1,C_1=1\)

性質

注:為避免符號重復本文所有公式將以 \(M_n\) 表示卡特蘭數,即明安圖數的拼音首字母。

符合通項公式:

\[M_{n}=C_{2 n}^{n}-C_{2 n}^{n+1}=\frac{C_{2 n}^{n}}{n+1}\left(n \geq 2, n \in N _{+}\right) \]

那么可以推出如下公式:

\[\begin{aligned} M_{n+1} &=\frac{M_{n}(4 n-2)}{n+2} & \\ M_{n} &=\left\{ \begin{array}{ll} \sum_{i=1}^{n} M_{i-1} M_{n-i} & n \geq 2, n \in N _{+} \\ 1 & n=0,1 \end{array}\right.\\ M_{n} &= \begin{bmatrix} 2 n \\ n \end{bmatrix}- \begin{bmatrix} 2 n \\ n-1 \end{bmatrix} \end{aligned} \]

基本原理

先來看一個問題:

對於 \(n\) 對括號,求共有多少種合法的匹配方案數。

其中括號的合法匹配方式為:一個左括號對應一個右括號,且左括號必須要在右括號前面出現。

這里我們用 +1 表示 “ \((\) ” ,用 -1 表示 “ \()\) ”。

那么顯然,對於一組合法的括號序列,該序列的前綴和必然大於或等於 \(0\) ;相反,若該括號序列不合法,其前綴和必然存在小於 \(0\) 的情況。

首先給出一個序列:

()(())()

該序列可以表示為

+1 -1 +1 +1 -1 -1 +1 -1

顯然這是一個非法序列。

對於像這樣的一個非法序列,找到第一個前綴和小於 \(0\) 的括號,並對該前綴中的每一個數進行取反。

上述例子便可以得到

-1 +1 +1 +1 -1 +1 +1 -1

此時該序列中共有 \(3+1+1=5\)+1\(4-1=3\)-1 。不難看出,第一個小於 \(0\) 的前綴和必定為 \(-1\) ,即 \(-1\)\(+1\) 多一個,取反后則 \(-1\)\(+1\) 少一個。這樣總體上看,由於二者數量原本相同,所以 \(+1\) 必定變為 \(n+1\) 個,\(-1\) 則變為 \(n-1\) 個。

由此,該結論可以推廣:

對於 \(n\) 對括號的每種非法匹配序列 \(A\),一定會有一個含有 \(n+1\)\(+1\)\(n-1\)\(-1\) 的序列 \(B\) 與其一一對應。

而序列 \(B\) 的數量可以通過 \(C_{2n}^{n+1}\) 計算,即非法序列的數量為 \(C_{2n}^{n+1}\)

而序列的總數量為 \(C_{2n}^n\) (從 \(2n\) 個位置中選擇 \(n\) 個位置放左括號,不考慮先后順序),則合法的匹配序列數量為:

\[C_{2 n}^{n}-C_{2 n}^{n+1}=\cfrac{C_{2 n}^{n}}{n+1} \]

由此便推導出了卡特蘭數的通項公式。

應用

P1044 [NOIP2003 普及組] 棧

直接由基本原理可以推出:

公式 1

\[H_n=\cfrac{H_{n−1} \times 4 \times n−2}{n+1} \]

代碼:

/*

Name: P1044 [NOIP2003 普及組] 棧

Solution: 


By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

#define int long long

using namespace std;
/*==================================================快讀*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定義變量*/
const int _ = 110;

int n;
int h[_];
/*=============================================自定義函數*/

/*=================================================主函數*/
signed main()
{
    h[0] = 1;
    h[1] = 1;
    n = read();
    for (int i = 2; i <= n; i++)
        h[i] += h[i - 1] * (4 * i - 2) / (i + 1);
    printf("%lld\n", h[n]);
    return 0;
}

公式 2

\[H_n=H_0 \times H_{n-1}+H_1 \times H_{n-2} + \cdots + H_{n-1} \times H_0 (n \geq 2) \]

代碼:

/*

Name: P1044 [NOIP2003 普及組] 棧

Solution: 


By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

#define int long long

using namespace std;
/*==================================================快讀*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定義變量*/
const int _ = 110;

int n;
int h[_];
/*=============================================自定義函數*/

/*=================================================主函數*/
signed main()
{
    h[0] = 1;
    h[1] = 1;
    n = read();
    for (int i = 2; i <= n; i++)
        for (int j = 0; j < i; j++)
            h[i] += h[j] * h[i - j - 1];
    printf("%lld\n", h[n]);
    return 0;
}

公式 3

\[H_n =\cfrac{C_{2n}^n}{n+1}(n=0,1,2,\cdots) \]

其中

\[C_m^n = C_{m-1}^{n-1} + C_{m-1}^n \]

並且規定

\[C_n^0=1, C_n^n=1, C_0^0=1 \]

代碼:

/*

Name: P1044 [NOIP2003 普及組] 棧

Solution: 


By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

#define int long long

using namespace std;
/*==================================================快讀*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定義變量*/
const int _ = 110;

int n;
int h[_ << 1][_];
/*=============================================自定義函數*/

/*=================================================主函數*/
signed main()
{
    n = read();
    for (int i = 1; i <= n << 1; i++)
    {
        h[i][0] = 1;
        h[i][i] = 1;
        for (int j = 1; j < i; j++)
        {
            h[i][j] = h[i - 1][j] + h[i - 1][j - 1];
        }
    }
    printf("%lld\n", h[n << 1][n] / (n + 1));
    return 0;
}

公式 4

\[H_n=C_{2n}^n−C_{2n}^{n−1}(n=0,1,2,\cdots) \]

代碼:

/*

Name: P1044 [NOIP2003 普及組] 棧

Solution: 


By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

#define int long long

using namespace std;
/*==================================================快讀*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定義變量*/
const int _ = 110;

int n;
int h[_ << 1][_];
/*=============================================自定義函數*/

/*=================================================主函數*/
signed main()
{
    n = read();
    for (int i = 1; i <= n << 1; i++)
    {
        h[i][0] = 1;
        h[i][i] = 1;
        for (int j = 1; j < i; j++)
            h[i][j] = h[i - 1][j] + h[i - 1][j - 1];
    }
    printf("%lld\n", h[n << 1][n] - h[n << 1][n - 1]);
    return 0;
}

如果還有其他公式歡迎聯系博主!(博主最多推四個了。。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM