AT5202 [AGC038E] Gachapon

发现题目所求即为最晚达到出现次数的整数的期望次数,考虑 \(\text{min-max}\) 容斥,将其转化为最早达到出现次数的整数的期望次数:

\[\large E(\max(S) )=\sum_{T\subseteq S}(-1)^{|T|+1}E(\min(T)) \]

设集合 \(T=\{ x_1,x_2,\dots,x_m \}\),考虑如何计算该集合的贡献,因为期望的线性性,所以直接求和所有未达到出现次数的状态的期望次数即可,得:

\[\large\begin{aligned} &(-1)^{|T|+1}E(\min(T)) \\ =&(-1)^{m+1}\sum_{i \geqslant 0} \left( \frac{s-\sum a_{x_i}}{s} \right)^i\sum_{0 \leqslant c_i < b_{x_i}} \frac{(\sum c_i)!}{\prod(c_i!)}\prod\left( \frac{a_{x_i}}{\sum a_{x_i}} \right)^{c_i} \\ =&(-1)^{m+1}\frac{s}{\sum a_{x_i}}\sum_{0 \leqslant c_i < b_{x_i}} \frac{(\sum c_i)!}{\prod(c_i!)}\prod\left( \frac{a_{x_i}}{\sum a_{x_i}} \right)^{c_i} \\ \end{aligned} \]

第一项为容斥系数,第二项为随机到该集合元素的期望次数,第三项是可重集排列,因为整数的出现顺序需要考虑,第四项为集合内每个整数随机到的概率。

发现式子主要和 \(\sum a_{x_i},\sum c_i\) 有关,可以考虑 \(DP\) 来进行计算。设 \(f_{i,j,k}\) 为考虑了前 \(i\) 个数,\(\sum a_{x_i}\)\(j\)\(\sum c_i\)\(k\) 的所有集合按上面式子去掉与 \(\sum a_{x_i},\sum c_i\) 有关的项的乘积之和。

转移为考虑是否加入第 \(i\) 个数,加入就考虑第 \(i\) 个数和其出现次数对式子的贡献。最后枚举 \(\sum a_{x_i},\sum c_i\) 即可计算答案。

#include<bits/stdc++.h>
#define maxn 410
#define all 400
#define p 998244353
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,s1,s2;
ll ans;
int a[maxn],b[maxn];
ll f[maxn][maxn][maxn],inv[maxn];
void init()
{
    inv[0]=inv[1]=1;
    for(int i=2;i<=all;++i) inv[i]=(p-p/i)*inv[p%i]%p;
}
int main()
{
    init(),read(n);
    for(int i=1;i<=n;++i)
        read(a[i]),read(b[i]),s1+=a[i],s2+=b[i];
    f[0][0][0]=p-1;
    for(int i=1;i<=n;++i)
    {
        ll v=1;
        for(int j=0;j<=s1;++j)
            for(int k=0;k<=s2;++k)
                f[i][j][k]=f[i-1][j][k];
        for(int t=0;t<b[i];++t,v=v*a[i]%p*inv[t]%p)
            for(int j=a[i];j<=s1;++j)
                for(int k=t;k<=s2;++k)
                    f[i][j][k]=(f[i][j][k]-f[i-1][j-a[i]][k-t]*v%p+p)%p;
    }
    for(int j=1;j<=s1;++j)
    {
        ll v=1;
        for(int k=0;k<=s2;++k,v=v*k%p*inv[j]%p)
            ans=(ans+f[n][j][k]*s1%p*inv[j]%p*v%p)%p;
    }
    printf("%lld",ans);
    return 0;
}
posted @ 2020-09-27 21:11  lhm_liu  阅读(330)  评论(0编辑  收藏  举报