重返现世
min-max 容斥,DP
记 \(\min\limits_k\{S\}\) 表示 \(S\) 中出现至少 \(k\) 个元素的期望时间
答案便为 \(\min\limits_{k} \{U\}, U = \{n \cdot 1\}\)
考虑到 \(k\) 很大,而 \(n - k\) 很小,所以转化一下
\(\min\limits_k \{U\} = \max\limits_{n - k + 1} \{U\}\)
记 \(k' = n - k + 1\) 再根据扩展 min-max 容斥,得
\(\max\limits_{k'} \{S\} = \sum\limits_{T \subseteq S} (-1) ^ {|T| - k'} \begin{pmatrix}|T| - 1\\k'- 1\end{pmatrix} \min\{T\}\)
还是根据几何分布,有 \(\min\{T\} = \frac m {\sum_{i\in S} p_i}\)
但这样直接做的时间复杂度是 \(O(2^n)\) 的,考虑换种做法
设 \(f_{i, j,k}\) 表示前 \(i\) 个数中的一些数组成集合 \(S\) ,\(\sum_{i \in S} p_i = j\) 时,\(\sum\limits_{T\subseteq S} (-1)^{|T| - k}\begin{pmatrix}|T| - 1\\k - 1\end{pmatrix}\) 的值
考虑第 \(i\) 个数选不选
-
第 \(i\) 个数不选:\(f_{i, j, k} = f_{i - 1, j, k}\)
-
第 \(i\) 个数选:
\[\begin{aligned} f_{i, j, k} &= \sum\limits_{T\subseteq S} (-1)^{|T| - k} \begin{pmatrix}|T| - 1\\k - 1\end{pmatrix} \\ &= \sum\limits_{T\subseteq S} (-1)^{|T| - k} \begin{pmatrix} \begin{pmatrix}|T| - 1 - 1\\ k - 1 - 1\end{pmatrix} + \begin{pmatrix}|T| - 1 - 1\\k - 1\end{pmatrix} \end{pmatrix} \\ &= \sum\limits_{T\subseteq S} (-1)^{(|T| - 1) - (k - 1)} \begin{pmatrix}(|T| - 1) - 1\\(k - 1) - 1\end{pmatrix} + \sum\limits_{T\subseteq S} (-1)^{|T| - k} \begin{pmatrix}|T| - 1 - 1\\k - 1\end{pmatrix} \\ &= f_{i - 1, j - p_i, k - 1} - \sum\limits_{T\subseteq S} (-1)^{(|T| - 1) - k} \begin{pmatrix}(|T| - 1) - 1\\k - 1\end{pmatrix} \\ &= f_{i - 1, j - p_i, k - 1} - f_{i - 1, j - p_i, k} \end{aligned} \]
综上,\(f_{i,j, k} = f_{i - 1, j, k} + f_{i - 1,j - p_i, k - 1} - f_{i - 1, j - p_i, k}\)
当 \(i = 0, j = 0, k = 0\) 时,带入定义式有 \(f_{0, 0, 0} = 0\)
时间复杂度:\(O(n m (n - k + 1))\) ,滚动数组优化后空间复杂度:\(O(m(n - m + 1))\)
#include <bits/stdc++.h>
#define re register
#define int long long
// #define pair pair<int, int>
// #define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout);
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
using namespace std;
inline int read()
{
re int x = 0, f = 0;
re char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = 1; ch = getchar();}
while (isdigit(ch)) {x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return f ? -x : x;
}
inline string getstr()
{
string res = "";
re char ch = getchar();
while (isspace(ch)) ch = getchar();
while (!isspace(ch)) res.push_back(ch), ch = getchar();
return res;
}
const int N = 1e3 + 3, P = 998244353, M = 1e4 + 4;
int n, K, m;
int p[N], f[2][M][12], inv[M];
signed main()
{
n = read(), K = n + 1 - read(), m = read();
inv[1] = 1;
for (re int i = 2; i <= m; ++i) inv[i] = P - P / i * inv[P % i] % P;
for (re int i = 1; i <= n; ++i) p[i] = read();
re bool flag = 1;
for (re int i = 1; i <= n; ++i, flag ^= 1)
{
for (re int j = 1; j <= m; ++j)
{
for (re int k = 1; k <= K; ++k)
{
f[flag][j][k] = f[flag ^ 1][j][k];
if (j < p[i]) continue;
if (j == p[i] && k == 1) f[flag][j][k]++;
else
{
f[flag][j][k] = (f[flag][j][k] + f[flag ^ 1][j - p[i]][k - 1] - f[flag ^ 1][j - p[i]][k]) % P;
if (f[flag][j][k] < 0) f[flag][j][k] += P;
}
}
}
}
flag ^= 1;
int ans = 0;
for (re int i = 1; i <= m; ++i) ans = (ans + f[flag][i][K] * m % P * inv[i] % P) % P;
printf("%lld", ans);
return 0;
}