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

题目链接

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

思路:我们可以设入栈为 0 0 ,出栈为 1 1 ,则满足题意的 01 01 串,前 m m 长度的 01 01 串中, 1 1 0 0 要少 k k 个,且每个前缀串的 0 0 的数量要不少于 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 ) = C 2 n n ( n + 1 ) h(n)=\frac{C_{2n}^n}{(n+1)}
拓展到一般情况:
比如一个 01 01 串,要求有 n n 1 1 m m 0 0 ,且每个前缀子串的 1 1 的个数要不小于 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} (此情况为串中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! (此情况为串中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;
}

猜你喜欢

转载自blog.csdn.net/a302549450/article/details/86934451
今日推荐