题解 LA4064

题目大意 多组数据,每组数据给定一个正整数 \(n(n\leq 1200)\) 和平面内 \(n\) 个点的坐标。要求输出所有锐角和直角三角形的个数。

分析 这道题和 UVa 11529 特别像,就连数据范围也一样。

我们从反面出发,统计钝角三角形的个数,也就是钝角的个数(为什么)。那么使用与那道题相同的做法,枚举每个点作为原点,算出其他点到原点的极角,排序。然后枚举每个点 \(A\) 用两个指针维护 \([ang_A+\frac{\pi}{2},ang_A+\pi]\) 中的所有点的个数,这就是钝角的个数。由于满足单调性所以不会增加复杂度,总体复杂度为 \(O(n^2\log n)\)

注意精度问题,坐标最好存成浮点数,我因为这个 WA 了 \(3\) 次。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1205;
const double PI = acos(-1.0), eps = 1E-10;

ll n, t, tot, now1, now2;
ll ans, cnt;
double ang[maxn * 2];
struct Point {
	double x, y;
} p[maxn];

ll C(ll n, ll m)
{
	if(n < m) return 0;
	
	ll res = 1;
	for(ll i = 1; i <= m; ++i)
		res = res * (n - i + 1) / i;
	return res;
}

ll count(int x)
{
	tot = 0, now1 = 1, now2 = 1, cnt = 0;	
	for(ll i = 1; i <= n; ++i) {
		if(i == x) continue;
		ang[++tot] = atan2(p[i].y - p[x].y, p[i].x - p[x].x);
		
		if(ang[tot] < 0) ang[tot] += 2 * PI;
		ang[tot + n - 1] = ang[tot] + 2 * PI;
	}
	
	sort(ang + 1, ang + tot * 2 + 1);
	
	for(ll i = 1; i <= tot; ++i) {
		while(ang[now1] - ang[i] <= PI * 0.5 - eps) ++now1;
		while(ang[now2] - ang[i] < PI) ++now2;
		cnt += now2 - now1;
	}
	
	return cnt;
}

int main()
{
	while(~scanf("%lld", &n) && n) {
		ans = 0;
		
		for(int i = 1; i <= n; ++i)
			scanf("%lf%lf", &p[i].x, &p[i].y);
		
		for(int i = 1; i <= n; ++i)
			ans += count(i);
			
		printf("Scenario %lld:\nThere are %lld sites for making valid tracks\n", ++t, C(n, 3) - ans);
	}
}
posted @ 2020-02-12 01:06  whx1003  阅读(105)  评论(0编辑  收藏  举报