bzoj 2969: 矩形粉刷 概率期望

时间:2022-05-25 06:26:02

题目:

为了庆祝新的一年到来,小M决定要粉刷一个大木板。大木板实际上是一个W*H的方阵。小M得到了一个神奇的工具,这个工具只需要指定方阵中两个格子,就可以把这两格子为对角的,平行于木板边界的一个子矩形全部刷好。小M乐坏了,于是开始胡乱地使用这个工具。

假设小M每次选的两个格子都是完全随机的(方阵中每个格子被选中的概率是相等的),而且小M使用了K次工具,求木板上被小M粉刷过的格子个数的期望值是多少。

题解:

我们发现我们无法直接进行概率期望dp

因为状态无法记录.

而在这道题中被染色的格子的位置不同也决定着不同的状态.

所以我们考虑转化问题,我们可以分别计算出每个格子k次后被染成黑色的概率.

然后我们求概率之和即为期望.

所以我们把问题转化成了求概率。

因为我们要求的是一个格子k次操作后被染成黑色的概率,而每次操作是染色一个子矩阵.

直接不好计算,所以考虑补集转化.

我们统计每个点在k次操作后仍然没有被染成黑色的概率。然后用1减即可。

至于怎么计算k次操作后没有被染成黑色的概率,我们算出一次染色没有被染到的概率.

再求k次方既可.

一次染色没有被染到的概率瞎XX搞一下就好了.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
int n,m;
#define sqr(x) ((x)*(x))
inline double calc(int i,int j){
double upside = .0;
upside += sqr(1.0*n*(j-1)) + sqr(1.0*(i-1)*m);
upside += sqr(1.0*(n-i)*m) + sqr(1.0*n*(m-j));
upside -= sqr(1.0*(i-1)*(j-1)) + sqr(1.0*(n-i)*(m-j));
upside -= sqr(1.0*(i-1)*(m-j)) + sqr(1.0*(n-i)*(j-1));
double dnside = sqr(1.0*n*m);
return upside/dnside;
}
inline double qpow(double x,int p){
double ret = 1.0;
for(;p;p>>=1,x=x*x) if(p&1) ret=ret*x;
return ret;
}
int main(){
int T;T = 1;
while(T--){
int k;read(k);read(n);read(m);
double ans = .0;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
ans += 1.0 - qpow(calc(i,j),k);
}
}
printf("%.0f\n",ans);
}
return 0;
}