AtCoder Beginner Contest 231 G - Balls in Boxes 简要题解

提供一个生成函数的推法。

考虑把最后的答案写出来:

\[\sum_{c_1+\cdots+c_n=k}\frac{k!}{n^k\prod_{i=1}^nc_i!}\prod_{i=1}^n(A_i+c_i) \]

这个式子的意思是把可能的一种增加方案\((c_1,\cdots,c_n)\)枚举出来,算出达到这种方案的情况数(\(\frac{k!}{\prod c_i!}\)),再算出概率和这种方案的贡献。

观察这个式子,和第\(i\)个元素相关的部分为\(\frac{A_i+c_i}{c_i!}\),把这东西写成EGF的形式就是\(F_i(x)=e^x(A_i+x)\),所以答案也就变成了:

\[[x^k]\frac{k!}{n^k}\prod_{i=1}^n e^x(A_i+x)=[x^k]\frac{k!}{n^k}e^{nx}\prod_{i=1}^n(A_i+x) \]

乘积部分是一个\(n\)次多项式,不需要分治ntt可以直接暴力算,又众所周知\(e^{nx}=\sum_{i=0}^{\infty} \frac{(nx)^i}{i!}\),把对应项乘起来就可以了。

namespace My_Math{
    #define N 100000

    int fac[N+100],invfac[N+100];

    int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
    int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
    int mul(int x,int y) {return 1ll*x*y%maxd;}
    ll qpow(ll x,int y)
    {
        ll ans=1;
        while (y)
        {
            if (y&1) ans=mul(ans,x);
            x=mul(x,x);y>>=1;
        }
        return ans;
    }
    int getinv(int x) {return qpow(x,maxd-2);}

    int C(int n,int m)
    {
        if ((n<m) || (n<0) || (m<0)) return 0;
        return mul(mul(fac[n],invfac[m]),invfac[n-m]);
    }

    void math_init()
    {
        fac[0]=invfac[0]=1;
        rep(i,1,N) fac[i]=mul(fac[i-1],i);
        invfac[N]=getinv(fac[N]);
        per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
    }
    #undef N
}
using namespace My_Math;

int n,k,f[N][N];

int main()
{
    f[0][0]=1;
    n=read();k=read();
    rep(i,1,n) 
    {
        int a=read();
        f[i][0]=mul(f[i-1][0],a);
        rep(j,1,i) f[i][j]=add(f[i-1][j-1],mul(f[i-1][j],a));
    }
    int ans=0,prod=1,inv=getinv(qpow(n,k));
    rep(i,0,min(k,n))
    {
        int tmp=mul(prod,qpow(n,k-i));        
        tmp=mul(tmp,inv);
        ans=add(ans,mul(tmp,f[n][i]));
        prod=mul(prod,k-i);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2021-12-13 09:29  EncodeTalker  阅读(116)  评论(2编辑  收藏  举报