[Gym 102978H] Harsh Comments

Gym - 102978H
tag:背包dp,概率期望,minmax反演


题意

\(n\)\(A\)物品,价值为\(a_i\)\(m\)\(B\)物品,价值为\(b_i\)。每次等概率删掉剩余物品中的一个\(\frac{val_i}{sum_{val}\ of\ remain}\),求删完\(A\)的期望步数

\(n,m\leq100,a_i\leq 100, \sum a_i+\sum b_i< 998244353\)

题解

考虑另一种做法,minmax反演

答案为\(max\{t_i\}=\sum_{S}(-1)^{|S|-1}min\{t_i\}\)
然后\(min\{E_i\}\)相当于只有一个\(A\)物品,价值为\(\sum E_i\),其余全是\(B\)物品。由于期望的线性性,答案为枚举一个\(B_i\)\(A\)之前删掉的概率再加起来再加1。

\(\sum_{S}(-1)^{|S|-1}\sum_{i\not\in S}\frac{p_i}{S_{sum}+p_i}\)
\(\sum_i\sum_{sum}\frac{p_i}{sum+p_i}\sum_S[i\not\in S][sum_S=sum](-1)^{|S|-1}\)

换个枚举顺序\(\sum_i\sum_S[i\not\in S](-1)^{|S|-1}\frac{p_i}{S_{sum}+p_i}\)

考虑到此题\(n\leq100,a_i\leq100\),所以枚举\(sum\)

\(\sum_i\sum_{sum}\frac{p_i}{sum+p_i}\sum_S[i\not\in S][sum_S=sum](-1)^{|S|-1}\)

如果不考虑\([i\not\in S]\),后面一堆式子可以背包解决\(O((n+m)S)\)

考虑\([i\not\in S]\),由于此题用的背包可逆,所以直接删掉\(i\)再加入即可

#include<bits/stdc++.h>
using namespace std;

template<typename T>
inline void Read(T &n){
	char ch; bool flag=false;
	while(!isdigit(ch=getchar())) if(ch=='-')flag=true;
	for(n=ch^48; isdigit(ch=getchar()); n=(n<<1)+(n<<3)+(ch^48));
	if(flag) n=-n;
}

const int MAXN = 105;
const int MOD = 998244353;

inline int inc(int a, int b){
    a += b;
    if(a>=MOD) a -= MOD;
    return a;
}

inline void iinc(int &a, int b){a = inc(a,b);}

inline int dec(int a, int b){
    a -= b;
    if(a<0) a += MOD;
    return a;
}

inline void ddec(int &a, int b){a = dec(a,b);}

inline int ksm(int base, int k=MOD-2){
    int res=1;
    while(k){
        if(k&1)
            res = 1ll*res*base%MOD;
        base = 1ll*base*base%MOD;
        k >>= 1;
    }
    return res;
}

int f[10005], n, m, S, a[MAXN], b[MAXN], ans;

inline void ins(int k){for(register int i=S; i>=0; i--) ddec(f[i+k],f[i]); S += k;}
inline void del(int k){S -= k; for(register int i=0; i<=S; i++) iinc(f[i+k],f[i]);}

int main(){
    Read(n); Read(m); f[0] = MOD-1; 
    for(register int i=1; i<=n; i++) Read(a[i]), ins(a[i]);
    for(register int i=1; i<=m; i++) Read(b[i]);
    for(register int i=1; i<=n; i++){
        del(a[i]);
        for(register int j=1; j<=S; j++) ans = (ans+1ll*a[i]*ksm(j+a[i])%MOD*f[j])%MOD; 
        ins(a[i]);
    }
    for(register int i=1; i<=m; i++) for(register int j=1; j<=S; j++) ans = (ans+1ll*b[i]*ksm(j+b[i])%MOD*f[j])%MOD;
    cout<<inc(ans,1)<<endl;
    return 0;
}
posted @ 2021-06-26 14:22  oisdoaiu  阅读(186)  评论(0编辑  收藏  举报