codeforces #313 div1 D

好神的题目!

首先我们运用pick定理A=S-B/2+1将要求的东西转化掉

之后分离变量,我们变成了求选取凸包面积的期望和求选取凸包在边界上的点的期望

我们先考虑求选取凸包面积的期望

如何计算凸多边形的面积,我们可以原点为划分点,计算凸包上的每个向量的叉积的和

如何计算凸包边界上的点,我们可以计算凸包上的每个向量上的点

那么我们可以考虑每个向量被计算的概率

显然p(i)-p(i+k)这个向量被计算的概率为(2^(n-k-1)-1)/(2^n-1-n-n*(n-1)/2)次

这样我们就可以O(n^2)的计算出答案啦

但是显然这是会T的,我们发现当k很大的时候,概率趋近于无穷小

当这个概率不会对精度产生足够的误差影响的时候我们就不用计算啦

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define eps 1e-20
using namespace std;

typedef long long LL;
const int maxn=100010;
long double ans;
LL n;
struct Point{
	LL x,y;
	void read(){scanf("%I64d%I64d",&x,&y);}
}p[maxn];
int GCD(int a,int b){return b==0?a:GCD(b,a%b);}

int main(){
	scanf("%I64d",&n);
	for(int i=0;i<n;++i)p[i].read();
	long double k=1-pow(0.5,n)*(n*n+n+2.0)/2.0;
	long double P=1.0/4.0/k;
	for(int i=1;i<n;++i){
		long double now=P-pow(0.5,n)/k;
		int tmp=i;
		for(int j=0;j<n;++j){
			ans+=now*(p[j].x*p[tmp].y-p[j].y*p[tmp].x-GCD(abs(p[j].x-p[tmp].x),abs(p[j].y-p[tmp].y)));
			tmp=(tmp+1)%n;
		}P/=2;
		if(P<eps)break;
	}
	printf("%.15lf
",(double)(ans/2+1.0));
	return 0;
}

  

原文地址:https://www.cnblogs.com/joyouth/p/5372644.html