bzoj 1913: [Apio2010]signaling 信号覆盖

每个凸四边形对答案的贡献是2,每个凹四边形对答案的贡献是1.
凹四边形贡献1是显然的,凸四边形贡献是2的原因是:
bzoj 1913: [Apio2010]signaling 信号覆盖_第1张图片
如果一个点在一个三角形的外接圆内,那么α+β<180°,那么,对于一个四点不共园的凸四边形,两对对顶点一定有且只有一对和<180°,所以对答案的贡献是2.
现在考虑如何求凸四边形个数和凹四边形个数,凹四边形比较好求。
枚举每个点,设其为p,统计有多少个三角形覆盖了这个点,那么,以这个点为中心的凹四边形就有多少个。
考虑补集转化,求有多少三角形不覆盖这个点。
将所有剩余点极角排序,对于每个点,找出和它角度最靠近180度的小于180度的点,选定这个点和这两个点之间的任何两个点构成的三角形都不包含那个p点,设他们之间,包含边界共有tot个点,那么三角形个数(tot-1)*(tot-2)/2.
    
    
    
    
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 3010
using namespace std;
struct PP { ll x,y; double slop;} p[N],q[N];
bool cmp (PP a,PP b) { return a.slop<b.slop;}
PP operator - (PP a,PP b) { return (PP){a.x-b.x,a.y-b.y,0};}
ll operator * (PP a,PP b) { return a.x*b.y-a.y*b.x;}
int main()
{
int n;
scanf("%d",&n);
ll A=0,B=0,C=1ll*(n-1)*(n-2)*(n-3)/6;
for (int i=1;i<=n;i++) scanf("%lld%lld",&p[i].x,&p[i].y);
for (int i=1;i<=n;i++)
{
int m=0;
for (int j=1;j<=n;j++)
if (i!=j)
{
q[++m]=p[j]-p[i];
q[m].slop=atan2(q[m].y,q[m].x);
}
sort(q+1,q+m+1,cmp);
for (int j=1;j<=m;j++) q[j+m]=q[j];
int now=1;
for (int j=1;j<=m;j++)
{
if (now<j) now=j;
while (now<(m<<1)&&q[j]*q[now+1]>0) now++;
B-=(now-j)*(now-j-1)/2;
}
B+=C;
}
A=1ll*n*(n-1)*(n-2)*(n-3)/24;
printf("%.6lf\n",(2.0*A-B)/(1ll*n*(n-1)*(n-2)/6)+3.0);
return 0;
}

你可能感兴趣的:(bzoj 1913: [Apio2010]signaling 信号覆盖)