题解 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);
}
}