T1 [JZOJ1385] 直角三角形

题目描述

  二维平面坐标系中有 $N$ 个位置不同的点。

  从 $N$ 个点选择 $3$ 个点,问有多少选法使得这 $3$ 个点形成直角三角形。

数据范围

  $3 \leq N \leq 1500$

分析

  再一次考场上正解写挂(怎么AC的一堆都是暴力卡常吸氧??)

  我们可以先枚举直角顶点,并求出其他点与该点连成的直线的斜率,再按斜率将点排序

  众所周知,两条相互垂直的直线斜率之积为 $-1$,所以两条垂直直线斜率一定异号(竖直和水平的直线特殊考虑)

  然后把斜率大于 $0$ 的点从大到小加入队列,再从大到小枚举斜率小于等于 $0$ 的点

  如果队首斜率与该点斜率之积小于 $-1$,那么它与后面将枚举的点也一定无法形成直角三角形,所以将其出队

  如果队首斜率与该点斜率之积大于 $-1$,那么该点与队列后面的点也一定无法形成直角三角形,所以直接判断下一个点

  这样时间复杂度就降至 $O(n^2 \, log \, n)$

  注意精度,$eps$ 尽量设小一点

2019-08-07 纪中NOIP模拟B组
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 2000000001.0
#define eps 1e-15
#define N 1505

int n, ans;

struct Point {
    int x, y;
    double k;
} p[N], q[N];

bool cmp(Point a, Point b) {
    return a.k > b.k;
}

double getk(Point a, Point b) {
    if (a.x == b.x) return inf;
    if (a.y == b.y) return 0;
    return (double)(b.y - a.y) / (b.x - a.x);
}

double Abs(double a) {
    if (a < 0) return -a;
    return a;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &p[i].x, &p[i].y);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < i; j++) q[j] = p[j];
        for (int j = i; j < n; j++) q[j] = p[j + 1];
        for (int j = 1; j < n; j++) q[j].k = getk(p[i], q[j]);
        sort(q + 1, q + n, cmp);
        queue<int> qu;
        int now = 0, last;
        while (q[++now].k > 0 && now < n) qu.push(now);
        for (; now < n; now++) {
            if (Abs(q[now].k - q[now - 1].k) < eps) {
                ans += last; continue;
            }
            last = 0;
            while (!qu.empty()) {
                int temp = qu.front();
                if (q[now].k == 0) {
                    if (q[temp].k == inf) qu.pop(), last++;
                    else break;
                }
                else {
                    double mul = q[now].k * q[temp].k;
                    if (Abs(mul + 1) < eps) qu.pop(), last++;
                    else if (mul + 1 < 0) qu.pop();
                    else break;
                }
            }
            ans += last;
        }
    }
    printf("%d", ans);
    
    return 0;
}
View Code

相关文章:

  • 2022-02-17
  • 2021-09-27
  • 2022-02-02
  • 2021-10-31
  • 2021-12-26
  • 2021-06-29
  • 2021-09-18
  • 2021-07-25
猜你喜欢
  • 2022-01-03
  • 2021-06-12
  • 2022-01-23
  • 2021-05-27
  • 2021-08-22
  • 2021-06-12
  • 2021-06-20
相关资源
相似解决方案