CodeForces 457 D.Bingo!(期望)

本文探讨了一个关于在n×n棋盘上放置不同数字,并从中选取子集进行标记的问题。通过对状态的数学分析,推导出得分期望值的计算公式,并提供了一段C++代码实现。

Description

m个不同的数字去放到一个n×n的棋盘中,然后随机从这m个数中取一个k子集,把棋盘中出现这k个数的位置标记,对于这个状态,其得分为2^{被完全标记的行数+被完全标记的列数},问得分的期望值,取期望值与1099的较小值输出

Input

三个整数n,m,k(1n300,n2m105,nkm)

Output

输出得分期望值与1099的较小值

Sample Input

1 2 1

Sample Output

2.5

Solution

一状态sta被标记行列数和为f(sta),则其对分数总和贡献为2f(sta),而注意到2f(sta)为从这些行列集中选出一子集方案数,设状态集为S,则得分期望值ans=1|S|staS2f(sta)=1|S|staSr=0nc=0n对于状态sta被完全标记的行列中选出rc列的方案数=r=0nc=0nCrnCcnpr,c

其中pr,c为选出的rc列被标记的概率,不考虑数字之间的排列,总方案数为Ckm,令z=n(r+c)rc为这rc列的格子数,则这z个位置必然在选出的k个数中,然后要从剩下的mz个数中选出kz个数字组成这k个数字,方案数Ckzmz,故pr,c=CkzmzCkm

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
ld f[maxn];
ld C(int n,int m)
{
    return f[n]-f[m]-f[n-m];
}
int main()
{
    f[0]=0;
    for(int i=1;i<=1e5;i++)f[i]=f[i-1]+log(1.0*i);
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    ld ans=0;
    for(int x=0;x<=n;x++)
        for(int y=0;y<=n;y++)
            if(n*(x+y)-x*y<=k)
            {
                int z=n*(x+y)-x*y;
                ld temp=C(n,x)+C(n,y)+C(m-z,k-z)-C(m,k);
                ans=min((ld)1e99,ans+exp(temp));
            }
    printf("%.10f\n",(double)ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值