传送门 我们发现凸四边形贡献为2,凹四边形贡献为1 而且四边形总个数=C(n,4) 所以我们只要知道凹四边形的个数就可以了 我们枚举在凹四边形中内角大于180的点 然后我们将其他点按照极角序排序 枚举极角差刚刚不小于π的两条边 那么这两条边之间的点和其中一条边上的点不包含中间点。 由于按照极角排序,那么枚举的时间复杂度是O(n)。 设p为不包含中间点的三角形个数,那么以该点为中间点的凹四边形个数为C(n-1,3)-p。 最后的期望即为(a+2*b)/C(n,3)。
#include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define N 1505 #define pi 3.1415926535898 #define ll long long using namespace std; struct point{double x,y;}a[N]; double ang[N*2]; ll tu,ao,tot; int top,n,t; ll C(ll n,ll m){ if (m==2) return n*(n-1)/2; if (m==3) return n*(n-1)*(n-2)/6; return n*(n-1)*(n-2)*(n-3)/24; } void calc(int x){ top=0; for (int i=1;i<=n;i++) if (i!=x) ang[++top]=atan2(a[i].y-a[x].y,a[i].x-a[x].x); sort(ang+1,ang+top+1); tot=0; t=top; for (int i=1;i<=t;i++) ang[++top]=ang[i]+2*pi; int p=1; for (int i=1;i<=t;i++){ p=max(p,i+1); while (p<=top&&ang[p]<ang[i]+pi) p++; if (p-i-1>=2) tot+=C(p-i-1,2); } ao+=C(n-1,3)-tot; } int main(){ scanf("%d",&n); if (n<=3){printf("0"); return 0;} for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); for (int i=1;i<=n;i++) calc(i); tu=C(n,4)-ao; printf("%lf",(double)(ao+tu*2)/C(n,3)+3); }