#计算几何,极角排序#洛谷 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;
}
posted @ 2025-07-13 04:44  lemondinosaur  阅读(11)  评论(0)    收藏  举报