跳转至

幼儿园篮球题

题意

蔡徐坤将会进行 S 场巡回篮球演出。由于他高超的技巧,蔡徐坤投没气的球一定能进,投有气的球一定不能进。

在第 i 场演出,场上会有 n_i 个蔡徐坤篮球,其中有 m_i 个是没气的,n_i-m_i 个是有气的。蔡徐坤会随机选择 k_i 个篮球投,若他投进了 x 个球,则该场演出的失败度为 x^L。求演出的期望失败度。

解析

对于每场表演,不难发现答案就是

\sum_{i=0}^ki^L\binom{m}{i}\binom{n-m}{k-i}

这样我们可以 O(SN) 回答询问,只能获得暴力分。考虑第二类斯特林数和幂的关系恒等式

n^m=\sum_{i=0}^n\binom{n}{i}\begin{Bmatrix}m\\i\end{Bmatrix}i!

这个恒等式的组合意义是,将 m 个有标号小球放入 n 个有标号盒子的方案数。用该式展开答案

\sum_{i=0}^k\binom{m}{i}\binom{n-m}{k-i}\sum_{j=0}^i\binom{i}{j}\begin{Bmatrix}L\\j\end{Bmatrix}j!

交换枚举顺序并展开二项式系数

\begin{aligned} &\sum_{i=0}^k\begin{Bmatrix}L\\i\end{Bmatrix}i!\sum_{j=i}^k\dfrac{m!}{(j-i)!i!(m-j)!}\binom{n-m}{k-j}\\ &=\sum_{i=0}^k\begin{Bmatrix}L\\i\end{Bmatrix}m!\sum_{j=i}^k\dfrac{1}{(j-i)!(m-j)!}\binom{n-m}{k-j}\\ &=\sum_{i=0}^k\begin{Bmatrix}L\\i\end{Bmatrix}m!\sum_{j=0}^{k-i}\dfrac{1}{j!(m-j-i)!}\binom{n-m}{k-j-i}\\ &=\sum_{i=0}^k\begin{Bmatrix}L\\i\end{Bmatrix}\dfrac{m!}{(m-i)!}\sum_{j=0}^{k-i}\binom{m-i}{j}\binom{n-m}{k-j-i} \end{aligned}

我们已经地将右侧的和式转化为范德蒙德卷积的形式了。这样答案就可以表示为

\sum_{i=0}^{\min(k,L)}\begin{Bmatrix}L\\i\end{Bmatrix}\dfrac{m!}{(m-i)!}\binom{n-i}{k-i}

我们可以在 O(L\log L) 的时间内求出同一行的所有 第二类斯特林数,继而在 O(SL) 的时间内回答 S 组询问。不要忘记比上 \binom{n}{k}

实现

#include <bits/stdc++.h>

typedef long long int ll;
const int maxn = 2e7 + 19, maxl = 2e5 + 19, mod = 998244353;

int qpow(int a, int b){
    int res = 1;
    while(b){
        if(b & 1)
            res = (ll)res * a % mod;
        a = (ll)a * a % mod, b >>= 1;
    }
    return res;
}

int rev[maxl << 2], w[maxl << 2];
void dft(std::vector<int>::iterator f, int n, int b){
    for(int i = 0; i < n; ++i)
        if(i < rev[i])
            std::swap(f[i], f[rev[i]]);
    for(int i = 2; i <= n; i <<= 1){
        w[0] = 1, w[1] = qpow(3, (mod - 1) / i); if(b == -1) w[1] = qpow(w[1], mod - 2);
        for(int j = 2; j < i / 2; ++j) w[j] = (ll)w[j - 1] * w[1] % mod;
        for(int j = 0; j < n; j += i){
            std::vector<int>::iterator g = f + j, h = f + j + i / 2;
            for(int k = 0; k < i / 2; ++k){
                int p = g[k], q = (ll)h[k] * w[k] % mod;
                g[k] = (p + q) % mod, h[k] = (p - q) % mod;
            }
        }
    }
    if(b == -1)
        for(int i = 0, inv = qpow(n, mod - 2); i < n; ++i)
            f[i] = (ll)f[i] * inv % mod;
}

std::vector<int> operator*(std::vector<int> F, std::vector<int> G){
    int N = 1;
    while(N < (int)(F.size() + G.size() - 1)) N <<= 1;
    for(int i = 0; i < N; ++i) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? N >> 1 : 0);
    F.resize(N), G.resize(N);
    dft(F.begin(), N, 1), dft(G.begin(), N, 1);
    for(int i = 0; i < N; ++i) F[i] = (ll)F[i] * G[i] % mod;
    dft(F.begin(), N, -1);
    F.resize(F.size() + G.size() - 1);
    return F;
}

std::vector<int> F, G;
int N, M, S, L;

int fact[maxn], ifact[maxn];
inline int binom(int n, int m){
    return (ll)fact[n] * ifact[n - m] % mod * ifact[m] % mod;
}

int main(){
    std::scanf("%d%d%d%d", &N, &M, &S, &L);
    if(N < L) N = L;

    fact[0] = 1;
    for(int i = 1; i <= N; ++i)
        fact[i] = (ll)fact[i - 1] * i % mod;
    ifact[N] = qpow(fact[N], mod - 2);
    for(int i = N - 1; i >= 0; --i)
        ifact[i] = (ll)ifact[i + 1] * (i + 1) % mod;

    F.resize(L + 1), G.resize(L + 1);
    for(int i = 0; i <= L; ++i)
        F[i] = (i & 1 ? -1 : 1) * ifact[i], G[i] = (ll)qpow(i, L) * ifact[i] % mod;
    F = F * G, F.resize(L + 1);

    while(S--){
        static int n, m, k, t, ans;
        std::scanf("%d%d%d", &n, &m, &k), t = std::min({k, L, m, n}), ans = 0;
        for(int i = 0; i <= t; ++i)
            ans = (ans + (ll)F[i] * fact[m] % mod * ifact[m - i] % mod * binom(n - i, k - i)) % mod;
        ans = (ll)ans * qpow(binom(n, k), mod - 2) % mod;
        std::printf("%d\n", (ans + mod) % mod);
    }
    return 0;
}

来源

洛谷 P2791 幼儿园篮球题

评论