AcWing 889. 满足条件的01序列

140 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

AcWing 889. 满足条件的01序列

给定 n 个 0 和 0 个 1,它们将按照某种顺序排成长度为 2n 的序列,求它们能排列成的所有序列中,能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列有多少个。

输出的答案对 10^9+7 取模。

输入格式

共一行,包含整数 n。

输出格式

共一行,包含一个整数,表示答案。

数据范围

1≤n≤10^5

输入样例:

3

输出样例:

5

思路

image.png

Snipaste_2022-07-26_13-36-23.png 将 0101 序列置于坐标系中,起点定于原点。若 00 表示向右走,11 表示向上走,那么任何前缀中 00 的个数不少于 11 的个数就转化为,路径上的任意一点,横坐标大于等于纵坐标。题目所求即为这样的合法路径数量。

下图中,表示从 (0,0)(0,0) 走到 (n,n)(n,n) 的路径,在绿线及以下表示合法,若触碰红线即不合法。

image.png

由图可知,任何一条不合法的路径(如黑色路径),都对应一条从 (0,0)(0,0) 走到 (n−1,n+1)(n−1,n+1) 的一条路径(如灰色路径)。而任何一条 (0,0)(0,0) 走到 (n−1,n+1)(n−1,n+1) 的路径,也对应了一条从 (0,0)(0,0) 走到 (n,n)(n,n) 的不合法路径。

答案如图,即卡特兰数。

卡特兰数模板

给定n个0和n个1,它们按照某种顺序排成长度为2n的序列,满足任意前缀中0的个数都不少于1的个数的序列的数量为: Cat(n) = C(2n, n) / (n + 1)

ac代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010, mod = 1e9 + 7;
int qmi(int a, int k, int p){
    int res = 1;
    while (k){
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}
int main(){
    int n;
    cin >> n;
    int a = n * 2, b = n;
    int res = 1;
    for (int i = a; i > a - b; i -- ) res = (LL)res * i % mod;
    for (int i = 1; i <= b; i ++ ) res = (LL)res * qmi(i, mod - 2, mod) % mod;
    res = (LL)res * qmi(n + 1, mod - 2, mod) % mod;
    cout << res << endl;
    return 0;
}