洛谷 重返现世(min-max+动态规划)
洛谷 重返现世(min-max+动态规划)
题目描述
为了打开返回现世的大门,Yopilla 需要制作开启大门的钥匙。Yopilla 所在的迷失大陆有 \(n\) 种原料,只需要集齐任意 \(k\) 种,就可以开始制作。
Yopilla 来到了迷失大陆的核心地域。每个单位时间,这片地域就会随机生成一种原料。每种原料被生成的概率是不同的,第 \(i\) 种原料被生成的概率是 \(\frac{p_i}{m}\) 。如果 Yopilla 没有这种原料,那么就可以进行收集。
Yopilla 急于知道,他收集到任意 \(k\) 种原料的期望时间,答案对 \(998244353\) 取模。
数据范围
对于 \(10 \%\) 的数据,\(p_1 = p_2 = ... = p_m\) 。
对于另外 \(10 \%\) 的数据,\(k = n\) 。
对于 \(70 \%\) 的数据,\(n \le 100\) 。
对于 \(100 \%\) 的数据,\(1 \le n \le 1000\) ,\(1 \le k \le n, \lvert n - k \rvert \le 10\) ,\(0 \le p_i \le m, \sum p = m, 1 \le m \le 10000\)
解题思路
min-max容斥及其扩展形式, 证明可以用容斥系数加二项式反演证明
可以直接背包来算, 是 \(\Theta(n^2m)\) 的
这样下去不行,换一种跟 k 相关的神仙思路
\(f[i][j][k]\) 表示前 i 种物品,概率和为 j,\(\sum_{i=k}^n (-1)^{i-k}{i-1 \choose k-1}\) 的值
由于组合数的性质 ${n \choose m} = {n-1 \choose m} + {n-1 \choose m-1} $ 和 每次转移都要乘上个负数得知上式
注意初值的设置
以下引用 ouuan 巨佬的解释
\(f_{i,0,0}\) 按定义计算结果为 \(0\)。
需要特殊处理的不是 \(f_{i,0,0}\),而是枚举 \(T\subseteq S\) 时没有枚举空集,所以当 \(j=p_i\) 时转移会出错。解决方法是 \(f_{i,p_i,k}\) 的包含 \(i\) 部分不从之前的状态转移,而是直接由定义计算,即把 \(T=\{i\}\) 代入定义式,这部分的值为 \((-1)^{1-k}\binom{0}{k-1}\),也就是 \(k=1\) 时为 \(1\),否则为 \(0\)。
总的 dp 方程:\(f_{i,j,k}=\begin{cases}f_{i-1,j,k}&(j<p_i)\\f_{i-1,j,k}+[k=1]&(j=p_i)\\f_{i-1,j,k}+f_{i-1,j-p_i,k-1}-f_{i-1,j-p_i,k}&(j>p_i)\end{cases}\)
当然,从结果上来看和 \(f_{i,0,0}=1\) 是一样的..
\(f[i][0][0]\) 设为 -1 也是可以的
const int K = 12, M = 10005;
const int P = 998244353;
ll f[K][M], inv[M], n, k, m;
int main() {
read(n), read(k), read(m), k = n - k + 1;
inv[0] = inv[1] = 1;
for (int i = 2;i <= m; i++) inv[i] = (P - P / i) * inv[P % i] % P;
for (int i = 1;i <= k; i++) f[i][0] = -1;
for (int i = 1;i <= n; i++) {
ll p; read(p);
for (int j = m; j >= p; j--) for (int q = k; q; q--)
f[q][j] = (f[q][j] + f[q-1][j-p] - f[q][j-p]) % P;
}
ll ans = 0;
for (int i = 1;i <= m; i++) ans = (ans + f[k][i] * inv[i]) % P;
write((ans * m % P + P) % P);
return 0;
}