#计算几何,极角排序#洛谷 3630 [APIO2010] 信号覆盖
分析
题目给出了一个很关键的信息,不存在四点共圆,在 \(O(n^4)\) 的算法基础上,
实际上就是外接圆后枚举的点构成的多边形,
这也就说明了要么是存在对角超过 \(180\) 度的凸多边形,要么就是凹多边形
后者能贡献 \(1\),而前者是 \(2\),考虑求出凹多边形,记其为 \(x\) 个,
那么答案为 \(\large \frac{x+2[\binom{n}{4}-x]}{\binom{n}{3}}+3\)
凹多边形考虑枚举凹点,剩余三个点不在凹点的同一侧,用 \(C(n-1,3)\) 减去同一侧的点,
那么枚举其中一点,用这条边找到其最远点,可以通过极角排序加上双指针实现,时间复杂度 \(O(n^2\log n)\)
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const double pi=acos(-1.0);
const int N=3011; int n;
struct Point{int x,y;}a[N];
long long ans,C[N][5]; double theta[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int main(){
n=iut(),C[0][0]=1;
for (int i=1;i<=2*n;++i){
C[i][0]=1;
for (int j=1;j<=4;++j) C[i][j]=C[i-1][j-1]+C[i-1][j];
}
for (int i=1;i<=n;++i) a[i].x=iut(),a[i].y=iut();
for (int i=1;i<=n;++i){
int tot=0;
for (int j=1;j<=n;++j)
if (j!=i){
theta[++tot]=atan2(a[j].y-a[i].y,a[j].x-a[i].x);
if (theta[tot]<0) theta[tot]+=2*pi;
}
sort(theta+1,theta+1+tot);
for (int j=1;j<=tot;++j) theta[j+tot]=theta[j]+2*pi;
int sum=0;
for (int j=1,k=1;j<=tot;++j){
while (k<=tot*2&&theta[k]-theta[j]<pi) ++k; --k;
sum+=C[k-j][2];
}
ans+=C[n-1][3]-sum;
}
printf("%lf",(ans+(C[n][4]-ans)*2.0)/C[n][3]+3);
return 0;
}

浙公网安备 33010602011771号