标签:can name algo span display 表示 codeforce 不同的 多次
给定\(N,M,K\),表示有一个\(N*N\)的空矩阵,\(M\)个不同的数。
随机地把\(M\)个数中的\(N^2\)个数丢进这个空矩阵中(\(M\ge N^2\))
再从\(M\)个数中随机选\(K\)个不同的数,在矩阵上将这\(K\)个数标记出来(如果有)。
设\(T\)的值为完全被标记的整行与整列个数。
求\(2^T\)的期望值与\(1e99\)的较小值。
首先,对于\(2^T\)这种奇怪的东西,我们可以将其理解为该种情况的所有子集个数。
即有些情况可能会被多次计算也是合法的,所以不用容斥。
则答案就是所有的\(T\)值出现个数的期望值。
然后有一个比较显然的想法:不妨枚举一下\(R,C\),表示至少有\(R\)整行,\(C\)整列被标记完。
则此时有一个\(C(N,R)\times C(N,C)\)表示在该情况下的\(T\)值总个数。
而这种方案的出现概率\(P[R][C]\)的值就为出现该情况数除以总情况数。
我们不妨设\(Z=(R+C)\times N-R\times C\),即这\(Z\)个数都会在所选的\(K\)个数中。
则有:
\[P[R][C]=\frac{C(M,K)\cdot A(K,Z)\cdot A(M-Z,N^2-Z)}{C(M,K)\cdot A(M,N^2)}\]
将该式子化简后得:
\[P[R][C]=\frac{C(M-Z,K-Z)}{C(M,K)}\]
即该情况对答案的贡献就为\(C(N,R)\times C(N,C)\times \frac{C(M-Z,K-Z)}{C(M,K)}\)
小注:
对于\(P[R][C]\)的理解:
对于答案的保存方式:
使用long double
来存储一个数的log()
值,
则乘法变加法,除法变减法,最后再统一出解。
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LD long double
const int MAXN=100005;
int N,M,K;
LD f[MAXN],Ans;
LD C(int x,int y){
return f[x]-f[y]-f[x-y];
}
int main(){
scanf("%d%d%d",&N,&M,&K);
for(int i=1;i<=1e5;i++)
f[i]=f[i-1]+log(1.0*i);
for(int i=0;i<=N;i++)
for(int j=0;j<=N;j++){
int z=N*(i+j)-i*j;
if(z>K)continue;
LD tmp=C(N,i)+C(N,j)+C(M-z,K-z)-C(M,K);
Ans=min((LD)(1e99),Ans+exp(tmp));
}
printf("%.10f\n",(double)Ans);
}
标签:can name algo span display 表示 codeforce 不同的 多次
原文地址:https://www.cnblogs.com/ftotl/p/11774330.html