Wannafly挑战赛9 - D 造一造 组合数学+卡特兰数

本文探讨了卡特兰数在解决特定算法问题中的应用,通过将入栈出栈序列转换为01串,利用卡特兰数的性质求解满足条件的序列数量。介绍了卡特兰数的递推式和通项公式,并提供了C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意:有 n n n 个节点,按顺序入栈出栈,中间当第 m m m 个数入栈之后,要求栈内有 k k k 个元素,问一共这 n n n 个节点全部入栈完,再全部出栈,有多少种入栈出栈的顺序。

思路:我们可以设入栈为 0 0 0,出栈为 1 1 1,则满足题意的 01 01 01 串,前 m m m 长度的 01 01 01 串中, 1 1 1 0 0 0 要少 k k k 个,且每个前缀串的 0 0 0 的数量要不少于 1 1 1 的数量,由此转换成求卡特兰数。

卡特兰数:
满足递推式: h ( n ) = h ( 0 ) ∗ h ( n − 1 ) + h ( 1 ) ∗ h ( n − 2 ) + . . . + h ( n − 1 ) ∗ h ( 0 ) ( n > = 2 ) h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2) h(n)=h(0)h(n1)+h(1)h(n2)+...+h(n1)h(0)(n>=2)
通项为: h ( n ) = C 2 n n ( n + 1 ) h(n)=\frac{C_{2n}^n}{(n+1)} h(n)=(n+1)C2nn
拓展到一般情况:
比如一个 01 01 01 串,要求有 n n n 1 1 1 m m m 0 0 0,且每个前缀子串的 1 1 1 的个数要不小于 0 0 0 的个数,则这样的串的数量即为卡特兰数。
C a t a l a n ( n , m ) = C n + m m − C n + m m − 1 Catalan(n,m)=C_{n+m}^{m}-C_{n+m}^{m-1} Catalan(nm)=Cn+mmCn+mm1(此情况为串中0代表元素相同,1代表元素相同)
C a t a l a n ( n , m ) = ( C n + m m − C n + m m − 1 ) ∗ n ! ∗ m ! Catalan(n,m)=(C_{n+m}^{m}-C_{n+m}^{m-1})*n!*m! Catalan(nm)=(Cn+mmCn+mm1)n!m!(此情况为串中0代表元素各不相同,1代表元素各不相同)

#include<iostream>
#include<climits>
using namespace std;
#define mod 1000000007
int inv[2000005];
int mul[2000005];
int fac[2000005];
int c(int n, int m)
{
    m = min(m, n - m);
    if (m < 0)
        return 0;
    return (((((1LL * mul[n]) % mod) * fac[m]) % mod) * fac[n - m]) % mod;
}
int solve(int m, int n)
{
    return (c(m + n, n) - c(m + n, n - 1) + mod) % mod;
}
int main()
{
    int T;
    int n, m, k;
    mul[0] = inv[0] = mul[1] = inv[1] = fac[0] = fac[1] = 1;
    for (int i = 2; i <= 2000000; ++i)
    {
        mul[i] = 1LL * mul[i - 1] * i % mod;
        inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
        fac[i] = 1LL * fac[i - 1] * inv[i] % mod;
    }
    cin >> T;
    while(T--)
    {
        cin >> n >> m >> k;
        cout << 1LL * solve(m - 1, m - k) * solve(n - m + k, n - m) % mod << '\n';
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值