bzoj2969 矩形粉刷
Description
为了庆祝新的一年到来,小M决定要粉刷一个大木板。大木板实际上是一个W*H的方阵。小M得到了一个神奇的工具,这个工具只需要指定方阵中两个格子,就可以把这两格子为对角的,平行于木板边界的一个子矩形全部刷好。小M乐坏了,于是开始胡乱地使用这个工具。
假设小M每次选的两个格子都是完全随机的(方阵中每个格子被选中的概率是相等的),而且小M使用了K次工具,求木板上被小M粉刷过的格子个数的期望值是多少。
Input
第一行是整数K,W,H
Output
一行,为答案,四舍五入保留到整数。
100% 的数据满足:\(1 \leq W,H \leq 1000, 0\leq K \leq 100\)
算被刷的格子个数和的期望,可以转化为每个格子被刷的概率和(和的期望=期望的和)
可以先算出每个格子一次有多少可能性不被刷,然后给他做一个\(k\)次方,也就是\(k\)次都不被刷的概率
然后用\(1\)减去这个概率,就是\(k\)次至少刷一次的概率
那么这个不被刷的概率,就要先求出有几个矩形不包含\((i,j)\),也就是选的两个点都在当前这个格子的同一方向,然后再除以矩形总数
例如\((i,j)\)表示在\(i\)行\(j\)列,那么在\((i,j)\)的上面有\((i-1)\cdot m\)个点,任意选两个点的方案数是\(((i-1)\cdot m)^2\)种方案
下,左,右也同理
不过这样计算会算重复,例如选的两个点都在\((i,j)\)的左上方,会在计算上和左的时候计算两遍,要再减一遍
以左上为例,要减去的方案数是\(((i-1)\cdot (j-1))^2\)
然后把重复的去掉就得到刷一次不被刷掉的概率了
一开始想按矩形四遍在哪一行/列来计算,直接计算能被刷掉的,但错了,应该是方法本身有问题
也有可能写错了。。
#include<cstdio>
#define reg register
inline double power(double a,int b){
double ret=1;
while(b){
if(b&1) ret*=a;
a*=a;b>>=1;
}
return ret;
}
inline double sqr(int x){
return (double)x*x;
}
int main(){
int k,n,m;
std::scanf("%d%d%d",&k,&n,&m);
double sum=sqr(n*m),ans=0;
for(reg int i=1;i<=n;i++){
for(reg int j=1;j<=m;j++){
double tmp;
tmp=sqr((i-1)*m)+sqr((n-i)*m)+sqr((j-1)*n)+sqr((m-j)*n);
tmp-=sqr((i-1)*(j-1))+sqr((n-i)*(m-j))+sqr((n-i)*(j-1))+sqr((m-j)*(i-1));
ans+=1-power(tmp/sum,k);
}
}
std::printf("%.0lf",ans);
}