河南萌新聯賽2024第(四)場題解

Proaes發表於2024-08-08

先給出比賽連結:
https://ac.nowcoder.com/acm/contest/88269

B 小雷的神奇電腦

Show Code B





C 崗位分配

已知每個志願者之間沒有區別,有不同的多個崗位且每個崗位至少有一個人,想到用組合數學隔板法來進行計數。

設 $ f_{n}^{m} $ 為n個崗位,m個人的分配情況數(注,任意崗位可沒有人)

然後即可透過隔板法求出 $ f_{n}^{m} = C_{n + m - 1}^{n - 1} $

下面以 $ f_{3}^{3} $ 為例:

總共有以下情況
(3,0,0) * 3
(2,1,0) * 6
(1,1,1) * 1

構造(3,0,0)可以 $ 1 2 3 \vert 0 \vert 0 $
構造(2,1,0)可以 $ 1 2 \vert 3 \vert 0 $
構造(1,1,1)可以 $ 1 \vert 2 \vert 3 $

本題每個崗位至少需要 $ a_i $ 個人那麼只需要把m減去 $ \sum\limits_{i = 1}^{n} a_i $

剩下的m就能用上面推出的 $ f_{n}^{m} $ 表示了

將i個候補加入崗位的貢獻是 $ f_{n}^{i} $

將之求和即可得到答案,就是 $ \sum\limits_{i = 0}^{m} f_{n}^{i} $

到這本題實際上已經完成了
但是還能繼續簡化

$
f_{n}^{m} = C_{n + m - 1}^{n - 1} = C_{n + m - 1}^{m}
$

$
\sum\limits_{i = 0}^{m} f_{n}^{i} = C_{n + i - 1}^{i}
$

\( 因為 C_{n}^{m} = C_{n - 1}^{m} + C_{n - 1}^{m - 1} \)

\( 所以 \sum\limits_{i = 0}^{m} f_{n}^{i} = C_{n + m}^{m} = f_{n + 1}^{m} ~~~(可用於字首和) \)

類似的:
\( \sum\limits_{i = 1}^{n} f_{i}^{m} = C_{n + m + 1}^{m + 1} = f_{n + 1}^{m + 1} \)

下面介紹求組合數的方法

1.楊輝三角法

\( 根據 C_{n}^{m} = C_{n - 1}^{m} + C_{n - 1}^{m - 1} ~~~ 可O(n^{2})預處理C_{n}^{m}的值 \)

2.公式法

\( 根據 C_{n}^{m} = \frac{n!}{m!(n-m)!} ~~~ 可O(n)預處理階乘,再透過公式計算 \)

下面給出AC程式碼,複雜度 $ O(n+m) $

Show Code C

constexpr ll mod = 998244353;
ll power(ll a , ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) {
            res = res * a % mod;
        }
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
constexpr ll maxn = 10000;
ll fact[maxn + 2];
ll inv[maxn + 2];
void initfact() {
    fact[0] = 1;
    for (ll i = 1; i <= maxn; ++ i) {
        fact[i] = fact[i - 1] * i % mod;
    }
    inv[maxn] = power(fact[maxn], mod - 2);
    for (ll i = maxn - 1; i >= 1; -- i) {
        inv[i] = inv[i + 1] * (i + 1ll) % mod;
    }
}
ll C(int n, int m) {
    if (m > n) {
        return 0;
    } else if (m == 0) {
        return 1;
    } else {
        return fact[n] * inv[m] % mod * inv[n - m] % mod;
    }
}
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    initfact();
    ll n, m, summ = 0;
    cin >> n >> m;
    ll ans = 0;
    vector a(n + 1);
    for (int i = 1; i <= n; ++ i) {
        cin >> a[i];
        m -= a[i];
        summ += a[i];
    }
    ans = C(n + m, m);
    cout << ans << "\n";
}




D 簡單的素數

Show Code E





F 小雷的算式

Show Code F





H 聰明且狡猾的惡魔

Show Code H





I 馬拉松

Show Code I





相關文章