ZJOI模拟 绝对伏特加【数学期望+组合数学+生成函数】

题目描述:

Alan A l a n 在玩骰子游戏, Alan A l a n 会玩 n n 轮骰子,每轮的数值在 [1,K] [ 1 , K ] 中随机出现。记 ai a i 表示 n n 轮投掷中,数值 i i 出现的次数,求 aF1aF2aFL a 1 F ∗ a 2 F ∗ … … a L F 的期望。答案对2003取模。
1n,k109,LF50000 1 ≤ n , k ≤ 10 9 , L ∗ F ≤ 50000

解题思路:

xi,j x i , j 表示第 j j 轮扔到i的概率,那么:

ans=E((x1,1++x1,n)F...(xL,1+...+xL,n)F) a n s = E ( ( x 1 , 1 + … + x 1 , n ) F ∗ . . . ∗ ( x L , 1 + . . . + x L , n ) F )

我们知道单个 xi,j=1k x i , j = 1 k ,而且和的期望等于期望的和,但只有在各个事件独立时积的期望才等于期望的积,而式子中 xi,a x i , a xj,a x j , a 显然不独立,所以不能直接算。

考虑将式子拆开,即

ans=E(ΠLi=1ΠFj=1xi,Ai,j)Ai,j[1,n] a n s = ∑ E ( Π i = 1 L Π j = 1 F x i , A i , j ) , A i , j ∈ [ 1 , n ]

注意到如果存在 ij,Ai,a=Aj,b i ≠ j , A i , a = A j , b ,即第 Ai,a A i , a 轮既扔到 i i ,又扔到j,这显然是不可能的,所以该项值为0;否则记所有 Ai,j A i , j 中出现的不同值个数为 t t ,那么这t个事件独立,该项值为 1kt 1 k t

考虑枚举在 [1,LF] [ 1 , L ∗ F ] 枚举 t t ,计算不存在ij,Ai,a=Aj,b的方案数,那么

ans=t=1LF(nt)t!ktG(t) a n s = ∑ t = 1 L ∗ F ( n t ) t ! k t G ( t )

G(t) G ( t ) 就表示已经选出了 t t 种值且第一次出现顺序下分配给LF Ai,j A i , j 的方案数。

用更直观的语言描述:有 L L 个有编号的盒子,每个盒子有 F F 个有编号的格子放球, LF L ∗ F 个球的编号要在 [1,n] [ 1 , n ] 中,不同编号有 t t 种,且任意两个盒子不能放有相同编号的球,求方案数。

假设一个盒子分到i种编号,由于我们已经枚举了编号出现的位置,所以编号之间没有顺序,相当于要把 F F 个格子分配到i个集合中,方案数显然是第二类斯特林数 SiF S F i

L L 个盒子一共有t种编号,考虑生成函数 g(x)=SiFxi g ( x ) = ∑ S F i x i ,那么 G(t) G ( t ) 即为 g(x)L g ( x ) L t t 次项系数,记为g(x)L[xt]

所以

ans=t=1LF(nt)t!ktg(x)L[xt]=t=1LFn!(nt)!ktg(x)L[xt] a n s = ∑ t = 1 L ∗ F ( n t ) t ! k t g ( x ) L [ x t ] = ∑ t = 1 L ∗ F n ! ( n − t ) ! k t g ( x ) L [ x t ]

注意到一旦 t2003 t ≥ 2003 n!(nt)! n ! ( n − t ) ! 就一定为0,所以只用考虑2003项即可。

预处理斯特林数,暴力做多项式乘法,时间复杂度为 O(2003F+20032logL) O ( 2003 F + 2003 2 l o g L )

#include<bits/stdc++.h>
using namespace std;
const int N=50005,mod=2003;
int n,K,L,F,s[N][2500];
int Pow(int x,int y)
{
    int res=1;x%=mod;
    for(;y;y>>=1,x=x*x%mod)
        if(y&1)res=res*x%mod;
    return res;
}
struct Poly
{
    int deg,a[N];
    Poly(){deg=0;memset(a,0,sizeof(a));}
    inline friend Poly mul(const Poly &A,const Poly &B)
    {
        Poly res;res.deg=min(mod,A.deg+B.deg);
        for(int i=0;i<=A.deg;i++)
            for(int j=0;j<=B.deg&&i+j<=mod;j++)
                res.a[i+j]=(res.a[i+j]+A.a[i]*B.a[j])%mod;
        return res;
    }
    inline friend Poly Pow(Poly A,int b)
    {
        Poly res;res.a[0]=1;
        for(;b;b>>=1,A=mul(A,A))
            if(b&1)res=mul(res,A);
        return res;
    }
}G;
void pre()
{
    for(int i=1;i<=F;i++)
    {
        s[i][1]=1;
        for(int j=2;j<=min(i,mod);j++)
            s[i][j]=(s[i-1][j-1]+s[i-1][j]*j)%mod;
    }
    G.deg=F;
    for(int i=1;i<=mod;i++)G.a[i]=s[F][i];
    G=Pow(G,L);
}
int main()
{
    freopen("vodka.in","r",stdin);
    freopen("vodka.out","w",stdout);
    scanf("%d%d%d%d",&n,&K,&L,&F);n%=mod,K%=mod;
    pre();
    int inv=Pow(K,mod-2),num=1,ans=0;
    for(int i=1;i<=L*F&&num;i++)
    {
        num=num*(n-i+1)%mod*inv%mod;
        ans=(ans+num*G.a[i])%mod;
    }
    cout<<ans<<'\n';
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值