• AtCoder Grand Contest 038 E: Gachapon


    题目传送门: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;
    }
    
  • 相关阅读:
    ctfhub技能树—信息泄露—备份文件下载—vim缓存
    ctfhub技能树—信息泄露—备份文件下载—bak文件
    ctfhub技能树—信息泄露—备份文件下载—网站源码
    RecyclerView错误
    R.java的生成规则
    各种编译不通过xcode
    Gradle
    xcode如何运行下载的demo工程
    xcode资源管理
    IOS代码片段
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/AGC038E.html
Copyright © 2020-2023  润新知