题目地址:https://codeforces.com/gym/102361/problem/A

题目:


n个给定点,q个询问点,每次询问给出一个坐标A,问从n中选定两个点B,C,有多少种方案使得ABC是个直角三角形。

 

解题思路:


标称的思路是从极角考虑的,训练的时候我以为是从极角考虑这个问题的,但是atan2,再加上极角+-,误差太大,我第二个样例就挂了(技艺不精QAQ)。

离线做,只需要开一个unorded_map。分直角顶点是询问点和给定点两种。

按斜率来考虑就简单很多,两个垂直的线段一定满足斜率相乘=-1,但是为了避免误差不需要求出真正的斜率,将斜率看作一个二元组(x,y)(约分使得gcd(x,y)=1),那么和它垂直的直线斜率为(-y,x)或者(y,-x)。

用unorded_map<Point, int>编译器会出现提示错误,“Call to implicitly-deleted default constructor of 'unordered_map<Point, int>'”,我目前还不清楚怎么改,把这个二元组hash一下即可,注意特判水平线和垂直线。

ll Hash(Point v)
{
    ll A = 2333, B = 5279, C = 998244353;
    return A*v.x + B*v.y + C;
}

 

ac代码:


#include<bits/stdc++.h>
using namespace std;
const int maxn = 2000 + 10;
const double pi = acos(-1.0);
const double eps = 1e-8;
typedef unsigned long long ll;
struct Point{
    int x, y;
    Point(int x = 0, int y = 0):x(x),y(y){}
};
typedef Point Vector;
Vector operator - (Vector A, Vector B)
{
    return Point(A.x-B.x, A.y-B.y);
}
bool operator == (Vector A, Vector B)
{
    return A.x==B.x && A.y==B.y;
}
Point p[maxn], qur[maxn];
int ans[maxn]={0};
unordered_map<ll, int> m;
int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a%b);
}
Point getSlope(Point A, Point B)
{
    Point v = A-B;
    if(v.x == 0) return Point(0, 1);
    if(v.y == 0) return Point(1, 0);
    int com = gcd(v.x, v.y);
    v.x/=com; v.y/=com;
    return v;
}
ll Hash(Point v)
{
    ll A = 2333, B = 5279, C = 998244353;
    return A*v.x + B*v.y + C;
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    int n, q;
    while(scanf("%d %d", &n, &q) == 2)
    {
        for (int i = 0; i < n; i++) scanf("%d %d", &p[i].x, &p[i].y);
        for (int i = 0; i < q; i++) scanf("%d %d", &qur[i].x, &qur[i].y);
        for (int i = 0; i < q; i++)//查询点是直角顶点
        {
            m.clear();
            for(int j = 0; j < n; j++)
            {
                Point v = getSlope(p[j], qur[i]);
                m[Hash(v)]++;
            }
            for(int j = 0; j < n; j++)
            {
                Point v = getSlope(p[j], qur[i]);
                if(v == Point(0,1) && m.count(Hash(Point(1,0)))) ans[i] += m[Hash(Point(1,0))];
                else if(v == Point(1,0) && m.count(Hash(Point(0,1)))) ans[i] += m[Hash(Point(0,1))];
                else ans[i] += (m[Hash(Point(-v.y, v.x))] + m[Hash(Point(v.y, -v.x))]);
            }
            ans[i] /= 2;
        }
        for (int i = 0; i < n; i++)//给定点是直角顶底
        {
            m.clear();
            for(int j = 0; j < n; j++)
            {
                if(i == j) continue;
                Point v = getSlope(p[i], p[j]);
                m[Hash(v)]++;
            }
            for(int j = 0; j < q; j++)
            {
                Point v = getSlope(p[i], qur[j]);
                if(v == Point(0,1) && m.count(Hash(Point(1,0)))) ans[j] += m[Hash(Point(1,0))];
                else if(v == Point(1,0) && m.count(Hash(Point(0,1)))) ans[j] += m[Hash(Point(0,1))];
                else ans[j] += (m[Hash(Point(-v.y, v.x))] + m[Hash(Point(v.y, -v.x))]);
            }
        }
        for (int i = 0; i < q; i++) printf("%d\n", ans[i]);
    }
    return 0;
}