Min-Max容斥

公式:

应用:

常用来求“每次选一个数,使每个数被选的次数至少到达某个值的期望次数”

首先我们要知道对于一个局面(比如第一个数选1次,第二个数选2次)的期望步数就是这个局面的概率分之一

证明:设期望为,概率为,那么,化简得

普遍情况:

个数,每个数有个权重,那么每一次选中第个数的概率就为,问每个数被选的次数至少到达的期望次数。

公式:

解释:

是得到一个指定集合内元素的期望时间,有重复元素的排列下,是对于集合内每个数的概率。
这个式子是怎么推出来的呢?
可以发现答案可以转化为每种状态的持续期望时间之和。那么就是状态改变的期望时间,就是每一种状态出现的概率。

例题:

E - Gachapon

题意:

个数,每个数有个权重,那么每一次选中第个数的概率就为,问每个数被选的次数至少到达的期望次数。

题解:

暴力做法就是枚举集合,然后通过上面给出的式子进行计算。

正解,考虑已经求出了一个集合的答案,现在要在这个集合里加入一个新的数

发现只要记录一下即可转移

代码:

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define gc getchar
#define int long long
const int N=405;
const int mod=998244353;
int n,a[N],b[N],jc[N],inv[N],sum[N],f[N][N][N];
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
int kuai(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b=b/2;
    }
    return res;
}
signed main()
{
    n=read();
    for(int i=1;i<=n;i++)a[i]=read(),b[i]=read();
    jc[0]=jc[1]=inv[0]=inv[1]=1;
    for(int i=2;i<=400;i++)jc[i]=jc[i-1]*i%mod;
    for(int i=2;i<=400;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(int i=2;i<=400;i++)inv[i]=inv[i]*inv[i-1]%mod;
    int s1=0,s2=0;
    f[0][0][0]=mod-1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=s1;j++)
            for(int k=0;k<=s2;k++)
                f[i][j][k]=f[i-1][j][k];
        sum[0]=1;
        for(int j=1;j<b[i];j++)sum[j]=sum[j-1]*a[i]%mod;
        for(int j=0;j<b[i];j++)sum[j]=sum[j]*inv[j]%mod;
        for(int j=0;j<=s1;j++)
            for(int k=0;k<=s2;k++)
                for(int p=0;p<b[i];p++)
                    f[i][j+p][k+a[i]]=(f[i][j+p][k+a[i]]-f[i-1][j][k]*sum[p]%mod+mod)%mod;
        s1+=b[i]-1;s2+=a[i];
    }
    int ans=0;
    for(int i=0;i<=s1;i++)
        for(int j=1;j<=s2;j++)
        {
            int x=f[n][i][j]*jc[i]%mod;
            x=x*kuai(kuai(j,mod-2),i)%mod;
            ans=(ans+x*s2%mod*kuai(j,mod-2)%mod)%mod;
        }
    cout<<ans;
}