概率题:lightoj1284

最经典的想法:计算各个点的概率,由于概率满足相加原理,所以求和即可


这个题的数据范围看上去是很大的,x,y,z都是100,k是10000

所以两种可能:

枚举坐标x,y,z,数据规模到100*100*100

枚举k,最大能到O(nlogn),也就是10000*log(10000)

才能够保证不超时


必须选择枚举坐标:原因是概率题,计算每个坐标的符合条件的可能性,再求和

那么思考:坐标(i,j,k)什么时候会被选中?

根据题意,必须i在(i1,i2)之间,j在(j1,j2)之间,k在(k1,k2)之间,该点才会被选中

这是k=1的情况

如果k=3可以吗?k=5可以吗?所以,奇数次方都是满足条件的

那么,对于给定的坐标,k=1时,取的概率是可以求的

根据乘法原理:点在区间内=横坐标在x的区间内*纵坐标在y的区间内*竖坐标在z的区间内

在区间内的计算方法=所有情况-不在区间内的情况(也就是两侧)

所以有了calc函数求得p


然后,如何求得各点的概率?

设F(n)表示n次中改变了奇数次

设G(n)表示n次中改变了偶数次

那么,G(n)=1-F(n)且F(n)=F(n-1)*(1-p)+G(n-1)*p

可以解得F(n)=F(n-1)*(1-2p)+p,初始值为F(0)=0,F(1)=p

高中数学知识:左右两边同时除以(1-2p)^n,得到一个可以迭代的式子,根据边界条件,计算得:F(n)=0.5-0.5*(1-2p)^n


想通了,其实代码很简单的:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <math.h>
#include <cmath>
using namespace std;

int t,n,x,y,z;
double p,ans;
double calc(int a,int b){
	return 1.0*b*b-1.0*(b-a)*(b-a)-(1.0)*(a-1)*(a-1);
}

int main(){
	//freopen("input.txt","r",stdin);
	scanf("%d",&t);
	for(int Case=1;Case<=t;Case++){
		ans=0;
		scanf("%d%d%d%d",&x,&y,&z,&n);
		for(int i=1;i<=x;i++)
		for(int j=1;j<=y;j++)
		for(int k=1;k<=z;k++){
			//概率等于符合条件的情况除以所有选择情况
			double p=calc(i,x)*calc(j,y)*calc(k,z)/x/x/y/y/z/z;
			ans+=0.5-0.5*pow(1-2*p,1.0*n);
		}
		printf("Case %d: %.8lf\n",Case,ans);
	}
	return 0;
}