zoukankan      html  css  js  c++  java
  • 洛谷 重返现世(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 vert le 10)(0 le p_i le m, sum p = m, 1 le m le 10000)

    解题思路

    min-max容斥及其扩展形式, 证明可以用容斥系数加二项式反演证明

    [max(S) = sum _{s in S} (-1)^{|s|+1}min(s)\ kmax(S) = sum_{s in S} {|s|-1choose k-1}(-1)^{|s|-k}min(s) ]

    [kmax(S) = sum_{i=k}^n (-1)^{i-k}{i-1 choose k-1}frac m{Sm}\ ]

    可以直接背包来算, 是 (Theta(n^2m))

    这样下去不行,换一种跟 k 相关的神仙思路

    (f[i][j][k]) 表示前 i 种物品,概率和为 j,(sum_{i=k}^n (-1)^{i-k}{i-1 choose k-1}) 的值

    [f[i][j][k] = f[i-1][j][k] + f[i-1][j-p][k-1] - f[i-1][j-p][k]\ ]

    由于组合数的性质 ${n choose m} = {n-1 choose m} + {n-1 choose m-1} $ 和 每次转移都要乘上个负数得知上式

    注意初值的设置

    以下引用 ouuan 巨佬的解释

    (f_{i,0,0}) 按定义计算结果为 (0)
    需要特殊处理的不是 (f_{i,0,0}),而是枚举 (Tsubseteq S) 时没有枚举空集,所以当 (j=p_i) 时转移会出错。解决方法是 (f_{i,p_i,k}) 的包含 (i) 部分不从之前的状态转移,而是直接由定义计算,即把 (T={i}) 代入定义式,这部分的值为 ((-1)^{1-k}inom{0}{k-1}),也就是 (k=1) 时为 (1),否则为 (0)
    总的 dp 方程:(f_{i,j,k}=egin{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;
    }
    
  • 相关阅读:
    【2020-01-28】陪伴即陪伴,擦汗即擦汗
    【2020-01-27】曼巴走了,但他还在
    【2020-01-26】今年,远亲不如近邻了
    【2020-01-25】新的一年,新的传统
    【2020-01-24】上天为这小女孩开了一扇小小窗
    【2020-01-23】故作假装的毛病
    day 31 html(二) 和css入门
    前端 day 30 html 基础一
    day 17python 面对对象之继承
    多并发编程基础 之协成
  • 原文地址:https://www.cnblogs.com/Hs-black/p/12908639.html
Copyright © 2011-2022 走看看