2021牛客多校四 G_product

G_product

题意 : 给出n, k, D. 求 D ! ∏ i = 1 n ( a i + k ) ! ( ∑ i = 1 n a i = D ) \frac{D!}{\prod_{i = 1}^{n}(a_i + k)!} (\sum_{i=1}^{n} a_i = D) i=1n(ai+k)!D!i=1nai=D

G-Product_2021牛客暑期多校训练营4 (nowcoder.com)

参考了欣君的题解。【算法题解】2021牛客暑期多校训练营#4_哔哩哔哩_bilibili

首先当 k = = 0 k == 0 k==0(没有k) 有个结论:
∑ a i ≥ 0 , ∑ a i = D ∏ i 1 a i = n D D ! \sum_{a_i \geq 0, \sum a_i = D} \prod_i \frac{1}{a_i} = \frac{n^D}{D!} ai0,ai=Diai1=D!nD

这里可以先考虑这个式子: D ! ∏ i = 1 n a i ! = n D \frac{D!}{\prod_{i = 1}^{n}a_i!} = n ^D i=1nai!D!=nD, 问题转化为D个球染1-n种颜色, a 1 … a n a_1 \dots a_n a1an 表示染了每种颜色的数量

题 ⇒ D ! ∑ a i ≥ k , ∑ a i = D + n k ∏ i 1 a i ! 题 \Rightarrow D! \sum_{a_i \geq k, \sum a_i = D+nk} \prod_i \frac{1}{a_i!} D!aik,ai=D+nkiai!1

先计算这个式子:
D ! ∑ a i ≥ 0 , ∑ a i = D + n k ∏ i 1 a i ! = n D + n k ( D + n k ) ! D ! D! \sum_{a_i \geq 0, \sum a_i = D+nk} \prod_i \frac{1}{a_i!} \\ =\frac{n^{D +nk}}{(D+nk)!} D! D!ai0,ai=D+nkiai!1=(D+nk)!nD+nkD!
再将 a i < k a_i < k ai<k 的部分容斥掉 :

考虑哪些 a i < k a_i < k ai<k ,枚举 a i a_i ai 的值, 但 n, D 不同, 需要DP

d p i , j dp_{i, j} dpi,j 表示将j个不同的球分成i组,每组不超过k-1个的方案数, d p i , j = ∑ t = 0 k − 1 d p i − 1 , j − t ( t j ) dp_{i, j} = \sum _{t = 0}^{k - 1} dp_{i - 1, j - t} \tbinom{t}{j} dpi,j=t=0k1dpi1,jt(jt), (这部分可以预处理,虽然D很大,但n ,k 很小)

注意转化后的 a i a_i ai ≥ k \ge k k的 ,

枚举有i个不合法的 a i a_i ai,这些 a i a_i ai的和为j,再对这部分分配一下,可以得到 ( i n ) ( j D + n k ) d p i , j \tbinom{i}{n} \tbinom{j}{D + nk} dp_{i , j} (ni)(D+nkj)dpi,j

剩余的都满足 a i ≥ k a_i \ge k aik , 这部分可以用隔板法直接求,

一共有n - i 组, D+nk - j 个球,每组球超过k个 的方案数

( n − i − 1 D − j ) \tbinom{n- i - 1}{D- j} (Djni1)

D很大好像不大好处理(

剩余的部分可以任意取,于是直接列一下就是$ (n - i) ^ {D+ nk - j}$, 因为会有重复计算,这里要容斥一下 ( − 1 ) i (- 1)^{i} (1)i

结合一下: ∑ i ∑ j ( − 1 ) i ( i n ) ( j D + n k ) d p i , j ( n − i ) D + n k − j \sum_{i} \sum_{j}(- 1)^{i} \tbinom{i}{n} \tbinom{j}{D + nk} dp_{i , j} (n - i) ^ {D+ nk - j} ij(1)i(ni)(D+nkj)dpi,j(ni)D+nkj

然后把 D ! ( D + n k ) ! \frac{D!}{(D+nk)!} (D+nk)!D! 乘上去

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll N = 60;
const ll M = 2510;
const ll mod = 998244353;

ll dp[N][M], c[M][M], cc[M];

ll n, d, k;

inline ll qpow(ll x, ll p) {
    ll res = 1;
    while (p) {
        if (p & 1) res = (res * x) % mod;
        x = (x * x) % mod;
        p >>= 1;
    }
    return res;
}

inline void init() {
    for (ll i = 0; i < M; ++i) {
        c[i][0] = 1;
        for (ll j = 1; j <= i; ++j) {
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
        }
    }
    dp[0][0] = 1;
    for (ll i = 1; i < N; ++i) {
        for (ll j = 0; j < M; ++j) {
            for (ll t = 0; t < k; ++t) {
                if(j < t) continue;
                dp[i][j] = (dp[i][j] + dp[i - 1][j - t] * c[j][t]% mod) % mod;
            }
        }
    }
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

    cin >> n >> k >> d;

    init();

    ll ans = 0;
    cc[0] = 1;
    for (ll i = 1; i < M; ++i) {
        cc[i] = cc[i - 1] * (d + n * k - i + 1 + mod) % mod * qpow(i, mod - 2) % mod;
    }

    for (ll i = 0; i <= n; ++i) {
        ll tmp = 0;
        for (ll j = 0; j <= i * (k - 1); ++j) {
            tmp = (tmp + cc[j] * dp[i][j] % mod * qpow(n - i, d + n * k - j) % mod) % mod;
        }
        tmp = tmp * c[n][i] % mod;
        if (i & 1) ans = (ans - tmp + mod) % mod;
        else ans = (ans + tmp) % mod;
    }

    for (ll i = d + 1; i <= d + n * k; ++i) {
        ans = ans * qpow(i, mod - 2) % mod;
    }
    cout << ans << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值