JZOJ 5680 绝对伏特加

Description

进行 n n 轮随机数生成,每轮的数值在[1, K K ]中随机出现。记ai表示 n n 轮投掷中,数值i出现的次数,求 (ΠLi=1ai)F ( Π i = 1 L a i ) F 的期望。答案对 2003 2003 取模。

Solution

0n,K109 0 ≤ n , K ≤ 10 9 , 0<F103 0 < F ≤ 10 3 , 0<LF50000 0 < L ∗ F ≤ 50000 , LK L ≤ K

Solution

先把每个数被选中的概率都看成1,最后答案乘上 1Kn 1 K n 即可。
考虑 1 1 ~L的贡献的生成函数 F(x) F ( x ) ,显然他们的生成函数都一样,考虑 EGF E G F

F(x)=i0iFxii! F ( x ) = ∑ i ≥ 0 i F x i i !

考虑用斯特林数把 iF i F 拆开,得

F(x)=i0xii!j=1F{Fj}ij F ( x ) = ∑ i ≥ 0 x i i ! ∑ j = 1 F { F j } i j _
F(x)=j=1F{Fj}ijxi(ij)! F ( x ) = ∑ j = 1 F { F j } ∑ i ≥ j x i ( i − j ) !
F(x)=j=1F{Fj}i0xi+ji! F ( x ) = ∑ j = 1 F { F j } ∑ i ≥ 0 x i + j i !
F(x)=j=1F{Fj}xji0xii! F ( x ) = ∑ j = 1 F { F j } x j ∑ i ≥ 0 x i i !
F(x)=j=1F{Fj}xjex F ( x ) = ∑ j = 1 F { F j } x j e x
F(x)=exj=1F{Fj}xj F ( x ) = e x ∑ j = 1 F { F j } x j

于是乎我们变得出了 1 1 ~L每一个数贡献的生成函数 F(x) F ( x ) ,则 1 1 ~L所有数贡献的生成函数即为 FL(x) F L ( x )

接下来再考虑剩下的 KL K − L 个数的贡献的生成函数,由于剩下的数不会对答案有贡献,只会让方案数有所增加,因此可以很容易得出剩下的数的生成函数 G(x) G ( x )

G(x)=i0(KL)ixii!=i0[(KL)x]ii!=eKL G ( x ) = ∑ i ≥ 0 ( K − L ) i x i i ! = ∑ i ≥ 0 [ ( K − L ) x ] i i ! = e K − L

所以答案就是让我们求 [xn] [ x n ] n!FL(x)G(x) n ! F L ( x ) G ( x ) mod 2003 m o d   2003

n!FL(x)G(x)=n!eK(j=1F{Fj}xj)L n ! F L ( x ) G ( x ) = n ! e K ( ∑ j = 1 F { F j } x j ) L

考虑 [xi]n!eK mod 2003 [ x i ] n ! e K   m o d   2003 的值
[xi]n!eK=nniKi [ x i ] n ! e K = n n − i _ K i
观察上式,当 i<n2003 i < n − 2003 [xi]n!eK [ x i ] n ! e K 一定为 2003 2003 的倍数,换言之,就是 n!eK n ! e K 中只有 n2003 n − 2003 至第 n n 项是有用的,同时也就意味着(j=1F{Fj}xj)L只有前 2003 2003 项是有用的,套上个快速幂暴力求即可。

时间复杂度 O(2003F+20032log L) O ( 2003 F + 2003 2 l o g   L )

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)

using namespace std;
typedef long long ll;
const ll N=2300,mo=2003;

int S[2][N];
int f[N],g[N];
ll n,K,L,F;

inline ll ksm(int o,ll t)
{
    int y=1;t=t%(mo-1);
    for(;t;t>>=1,o=o*o%mo)
    if(t&1)y=y*o%mo;
    return y;
}

inline int min(int a,int b)
{return a<b?a:b;} 

inline void zj()
{
    fd(i,mo,0){
        int op=0;
        fo(l,0,i)op=(op+g[l]*g[i-l])%mo;
        g[i]=op;
    }
}

inline void lj()
{
    fd(i,mo,0){
        int op=0;
        fo(l,0,i)op=(op+f[l]*g[i-l])%mo;
        f[i]=op;
    }
}

int main()
{
    cin>>n>>K>>L>>F;
    int v=0,u=0;
    S[0][0]=1;
    fo(i,1,F){
        v=u^1;
        S[v][0]=0;
        fo(l,1,min(i,mo))S[v][l]=(S[u][l-1]+S[u][l]*l)%mo;
        if(i<=mo)S[v][i]=1;
        u=v;
    }
    f[0]=1; fo(i,0,2003)g[i]=S[u][i];
    int r=ksm(K%mo,n),ny=ksm(K%mo,mo-2);
    for(;L;L>>=1,zj())if(L&1)lj();
    int op=1,ans=0;
    fo(i,0,mo){
        ans=(ans+f[i]*r%mo*op)%mo;
        r=r*ny%mo;
        op=op*((n-i)%mo)%mo;
    }
    int yy=ksm(K%mo,mo-2);
    ans=ans*ksm(yy,n)%mo;
    cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值