Min-Max容斥
公式:
应用:
常用来求“每次选一个数,使每个数被选的次数至少到达某个值的期望次数”
首先我们要知道对于一个局面(比如第一个数选1次,第二个数选2次)的期望步数就是这个局面的概率分之一。
证明:设期望为
,概率为
,那么
,化简得
 普遍情况:
个数,每个数有个权重
,那么每一次选中第
个数的概率就为
,问每个数被选的次数至少到达
的期望次数。
公式:!%7D%7B%5Csum%20c_i!%7D%20%5Cprod%20(%5Cfrac%7Ba%5Bx_i%5D%7D%7B%5Csum%20a%5Bx_i%5D%7D)%5E%7Bc_i%7D&preview=true)
 解释:
是得到一个指定集合内元素的期望时间,
有重复元素的排列下,
是对于集合内每个数的概率。
这个式子是怎么推出来的呢?
可以发现答案可以转化为每种状态的持续期望时间之和。那么就是状态改变的期望时间,
就是每一种状态出现的概率。
例题:
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;
} 
京公网安备 11010502036488号