YY模拟:绝对伏特加(数学期望)

题意:

Alan Alan 在玩骰子游戏, Alan Alan 会玩 n n 轮骰子,每轮的数值在[1,K] 中随机出现。记 ai a i 表示 n n 轮投掷中,数值i 出现的次数,求 aF1aF2...aFL a 1 F ∗ a 2 F ∗ . . . ∗ a L F 的期望。答案对 2003 2003 取模。

题解:
xi,j x i , j 表示第 i i 轮结果是否为j,那么:

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

展开多项式,考虑每个单项式的期望的和。 对于一个特定的单项式 ,是在每一个括号里面取 F F 项乘起来得到的,所以共有FL 项 ,我们把从第 i i 个括号中取的第j个数 xb,i x b , i b b 放入Ai,j中,就得到了一个大小为 FL F ∗ L A A 矩阵。所以每个单项式唯一对应一个A矩阵。

对于一个特定的 A A 矩阵,如果i,jAi,a=Aj,b,ij,那么这个单项式的期望为0,因为一轮骰子不可能出现两个数。

否则这个单项式的期望为 1Kt 1 K t , t t Ai,j的种类数。
枚举 t t , 问题变为了我们在FL的矩阵中填入 [1,n] [ 1 , n ] ,且不同种类数为 t t 的方案数。

按行考虑,我们先不考虑颜色种类和彼此的顺序,最后乘上(nt)t!即可,设 dpi,j d p i , j 表示一行第 i i 位出现j种数的方案数,则有 dpi,j=dpi1,j1+dpi1,jj d p i , j = d p i − 1 , j − 1 + d p i − 1 , j ∗ j
最后倍增做 L L 次背包(多项式乘法),然后枚举第几项即可。 注意对2003取模,后面的项因为要乘 t! t ! 被消掉的,所以只需要存 2003 2003 位。

时间复杂度: O(F2+20032logL) O ( F 2 + 2003 2 log ⁡ L )

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e3+50, mod=2003;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (LL)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
int n,K,L,F;
int fac[mod],dn[mod],dp[N][N],G[mod],f[mod],ipw[mod];
inline void mul(int *a,int *b,int *c) {
    static int tp[mod],tp2[mod];
    for(int i=0;i<mod;i++) tp[i]=a[i], tp2[i]=b[i], c[i]=0;
    for(int i=0;i<mod;i++)
        for(int j=0;j<=i;j++)
            c[i]=add(c[i],mul(tp[j],tp2[i-j]));
}
int main() {
    cin>>n>>K>>L>>F;
    const int invk=power(K,mod-2);
    ipw[0]=fac[0]=dn[0]=1;
    for(int i=1;i<mod;i++) ipw[i]=mul(ipw[i-1],invk), fac[i]=mul(fac[i-1],i);
    for(int i=1;i<mod;i++) dn[i]=mul(dn[i-1],n-i+1);
    dp[0][0]=1;
    for(int i=1;i<=F;i++)
        for(int j=1;j<=i;j++)
            dp[i][j]=add(mul(dp[i-1][j],j),dp[i-1][j-1]);
    for(int i=1;i<=F;i++) G[i]=dp[F][i];
    f[0]=1;
    for(int b=L;b;b>>=1,mul(G,G,G))
        if(b&1) mul(f,G,f);
    int ans=0;
    for(int i=1;i<mod && i<=n;i++)
        ans=add(ans,mul(dn[i],mul(ipw[i],f[i])));
    cout<<ans;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值