题目传送门:AGC038E。
题意简述
有 (N) 个物品,给定 (A_0 sim A_{N - 1}) 和 (B_0 sim B_{N - 1})。
每一个单位时间你会获得一个物品,第 (i) 个物品有 (dfrac{A_i}{sum_{j = 0}^{N - 1} A_j}) 的概率获得。
计算第一次对于每个 (i) 都有第 (i) 个物品获得至少 (B_i) 个的期望时间。
- (displaystyle sum_{i = 1}^{N - 1} A_i le 400)
- (displaystyle sum_{i = 1}^{N - 1} B_i le 400)。
题解
令 (displaystyle Sigma A = sum_{i = 0}^{N - 1} A_i) 以及 (displaystyle Sigma B = sum_{i = 0}^{N - 1} (B_i - 1))。
使用 Min-Max 容斥,转化为对于每个 ({0, 1, ldots , N - 1}) 的非空子集计算第一次子集中的任意一个物品获得至少 (B_i) 个的期望时间,如果集合大小为奇数,则对答案贡献 (1) 倍,否则贡献 (-1) 倍。
也就是满足子集中的所有物品获得的数量都少于 (B_i) 个的时刻数量,加上 (1)。
如果我们把开始的没有任何物品的状态也算作一个时刻,那么 (+1) 就省了。
现在考虑对于一个非空子集 (S subseteq {0, 1, ldots , N - 1}) 计算子集中的所有物品获得的数量都少于 (B_i) 个的时刻数量(包括初始时刻)。
这也就是对于每一种物品获得的状态,计算这种状态在所有可能情况下出现的期望次数(包括初始时刻),再求和。
我们枚举每一种状态,用 (x) 表示,其中 (x_i) 表示 (i) 获得的个数((i in S)),必须保证 (0 le x_i < B_i)。
接下来需要计算这种状态在所有可能情况下出现的期望次数。
注意到一旦第一次变成了这种状态,只要再次获得 (S) 中的物品,状态就会改变。
令 (P) 为一次获得 (S) 中的物品的概率,也就是 (dfrac{sum_{i in S} A_i}{Sigma A})。可以发现一旦第一次变成这种状态之后,状态会期望持续 (1 / P) 个时刻(包括第一次的时刻)。对于固定的 (S),(P) 都是不变的,所以只要求出每一种状态出现的概率再最后乘以 (1 / P) 就行了。
考虑计算每一种状态出现的概率,这时就不需要考虑 (S) 以外的物品的影响了,它们不会影响出现概率。
那么一种状态的概率就是存在一个获得 (S) 中物品的前缀满足 (i) 恰好出现了 (x_i) 次。
令 (displaystyle X = sum_{i in S} x_i) 以及 (displaystyle C = sum_{i in S} A_i),则概率就是 (displaystyle X! prod_{i in S} {left( frac{A_i}{C} ight)}^{x_i} frac{1}{(x_i)!}),这些阶乘来自于多重组合数。
利用乘法分配律,以 (X) 为 DP 的状态进行转移,我们就可以对于所有可能的状态求出这个概率的和,转移其实类似于指数型生成函数的卷积。
而如果需要对所有的 (S) 求和,也是类似的,需要注意处理一下容斥系数。然而对于不同的 (S),(C) 是不固定的,不过我们可以直接把 (C) 提出来,也就是 (displaystyle frac{X!}{C^X} prod_{i in S} frac{A_i^{x_i}}{(x_i)!}),然后 DP 的时候记录 (X, C) 两维状态即可。
这样依次加入 (N) 个物品,每次加入的时间复杂度为 (mathcal O (B_i X C)) 进行暴力转移。
下面是代码,时间复杂度为 (mathcal O({(Sigma B)}^2 Sigma A)):
#include <cstdio>
typedef long long LL;
const int Mod = 998244353;
const int MN = 405;
inline int qPow(int b, int e) {
int a = 1;
for (; e; e >>= 1, b = (LL)b * b % Mod)
if (e & 1) a = (LL)a * b % Mod;
return a;
}
int Fac[MN], iFac[MN];
void Init(int N) {
Fac[0] = 1;
for (int i = 1; i <= N; ++i) Fac[i] = (LL)Fac[i - 1] * i % Mod;
iFac[N] = qPow(Fac[N], Mod - 2);
for (int i = N; i >= 1; --i) iFac[i - 1] = (LL)iFac[i] * i % Mod;
}
int N, A[MN], B[MN], SA, SB;
int f[MN][MN], g[MN][MN], Ans;
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; ++i)
scanf("%d%d", &A[i], &B[i]),
SA += A[i], SB += B[i] - 1;
Init(SB);
SA = SB = 0;
f[0][0] = Mod - 1;
for (int i = 1; i <= N; ++i) {
for (int j = 0; j <= SA + A[i]; ++j)
for (int k = 0; k <= SB + B[i] - 1; ++k)
g[j][k] = 0;
for (int j = 0; j <= SA; ++j) {
int *G = g[j + A[i]];
for (int k = 0; k <= SB; ++k)
for (int x = 0, c = 1; x < B[i]; ++x, c = (LL)c * A[i] % Mod)
G[k + x] = (G[k + x] + (LL)c * iFac[x] % Mod * f[j][k]) % Mod;
}
SA += A[i], SB += B[i] - 1;
for (int j = 0; j <= SA; ++j)
for (int k = 0; k <= SB; ++k) {
f[j][k] -= g[j][k];
f[j][k] += (f[j][k] >> 31) & Mod;
}
}
for (int j = 1; j <= SA; ++j) {
int v = qPow(j, Mod - 2);
int c = (LL)SA * v % Mod;
for (int k = 0; k <= SB; ++k, c = (LL)c * v % Mod)
Ans = (Ans + (LL)Fac[k] * c % Mod * f[j][k]) % Mod;
}
printf("%d
", Ans);
return 0;
}