题目地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1913
题目大意:一个平面上n个点,随机选3个点构成一个圆,问期望有多少个点在这个圆内和圆上。数据保证没有4点共圆、3点共线和重点。
算法讨论:考虑四边形,凸四边形对答案的贡献为2,凹四边形对答案的贡献为1。设凹四边形个数为a,凸四边形个数为b,那么b=C(n,4)-a。枚举凹四边形的中间点,以中间点为原点,把其他点按照极角排序,枚举极角差刚刚不小于π的两条边,那么这两条边之间的点和其中一条边上的点不包含中间点。由于按照极角排序,那么枚举的时间复杂度是O(n)。设p为不包含中间点的三角形个数,那么以该点为中间点的凹四边形个数为C(n-1,3)-p。最后的期望即为(a+2*b)/C(n,3)。
Code:
#include <cmath>
#include <cstdio>
#include <algorithm>
#define N 1500
using namespace std;
const long double pi=acos(-1);
int n,cnt;
double tx,ty;
long long p,q;
long double x[N+10],y[N+10],point[N*2+10];
int main(){
#ifndef ONLINE_JUDGE
freopen("1913.in","r",stdin);
freopen("1913.out","w",stdout);
#endif
scanf("%d",&n);
if (n<4){puts("0");return 0;}
for (int i=1;i<=n;++i) scanf("%lf%lf",&tx,&ty),x[i]=(long double)tx,y[i]=(long double)ty;
for (int i=1;i<=n;++i){
int cnt=0;
long long res=0;
for (int j=1;j<=n;++j) if (i!=j) point[++cnt]=atan2(x[j]-x[i],y[j]-y[i]);
sort(point+1,point+cnt+1);
for (int j=1;j<n;++j) point[++cnt]=point[j]+pi*2;
for (int j=1,k=0;j<n;++j){
k=max(k,j+1);
while (k<=cnt && point[k]<point[j]+pi) k++;
if (k-j-1>1) res+=(k-j-1)*(k-j-2)/2;
}
p+=(long long)(n-1)*(n-2)*(n-3)/6-res;
}
q=(long long)n*(n-1)*(n-2)*(n-3)/24-p;
printf("%.6lf\n",(double)((long double)(p+2*q)/((long long)n*(n-1)*(n-2)/6)+3));
return 0;
}
By Charlie Pan
Aug 25,2014