题目链接:https://codeforces.com/gym/102361/problem/A
题意:给定二维平面上的\(n\)个点,\(q\)次询问,每次加入一个点,询问平面上有几个包含该点的直角三角形。
分析:这是一篇鸽了很久的题解,主要原因就是现场赛的时候这题惨遭卡常,锅++。现在回过头来想这题,主要问题出在现场赛时误判了\(map\)的时间复杂度,把极角排序的正确想法成功叉掉,以及现场赛时候的共线计数使用了\(gcd\),使得整体复杂度上升。(但还是有大佬拿gcd思想过了,我太菜了)现在学了一种共线计数的新想法,只需要重载就能实现,于是再用\(map\)来写一写这道题。。。
本题思路不难,将直角三角形分为两类,一类是以新加入点为直角顶点的直角三角形,另一类新加入点不作直角顶点。第一种情况,我们将新加入点与原有点之间构成的所有向量加入\(map\),然后通过点积为零的性质查找垂直的向量个数。(会计数两次,要除以二)另一类采取离线操作,我们将每个原有点当作直角顶点遍历,并将该点与另外原有点构成的向量加入\(map\),更新\(q\)个新加入点的直角三角形数量即可。
AC代码:
#pragma GCC target("avx") #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #include <bits/stdc++.h> #define SIZE 2010 #define rep(i, a, b) for (int i = a; i <= b; ++i) #define ll long long using namespace std; struct Point { ll x, y; Point() {} Point(ll a, ll b) :x(a), y(b) {} Point base() const{ if (x < 0 || (x == 0 && y < 0))return Point(-x, -y); return *this; } bool operator<(const Point& b)const { Point p1 = base(); Point p2 = b.base(); //如果共线,考虑是相同的索引 return p1.x * p2.y < p1.y * p2.x; } void input() { scanf("%lld %lld", &x, &y); } }p[SIZE]; Point operator *(Point a, ll t) { return Point(a.x * t, a.y * t); } //向量数乘 Point operator +(Point a, Point b) { return Point(a.x + b.x, a.y + b.y); } //向量加法 Point operator -(Point a, Point b) { return Point(b.x - a.x, b.y - a.y); } //向量减法 Point operator / (Point a, ll p) { return Point(a.x / p, a.y / p); } //向量数乘的除法形式 double Polarangle(Point a) { return atan2(a.y, a.x); } ll __gcd(ll a, ll b) { return b == 0 ? a : __gcd(b, a % b); } int n, q, cnt = 1; map<Point, int> MAP; int main() { scanf("%d %d", &n, &q); int m = q; vector<Point> vec(q + 1); vector<int> res(q + 1); rep(i, 1, n) p[i].input(); while (m--) { int ans = 0; Point tp; tp.input(); vec[cnt] = tp; rep(i, 1, n) { Point tmp = p[i] - tp; ++MAP[tmp]; } for (auto it : MAP) { Point tmp(-it.first.y, it.first.x); if (MAP.count(tmp)) ans += MAP[tmp] * it.second; } res[cnt++] = ans / 2; MAP.clear(); } rep(i, 1, n) { MAP.clear(); rep(j, 1, n) { if (i == j) continue; MAP[p[j] - p[i]]++; } rep(j, 1, q) { Point tp = vec[j] - p[i]; tp = Point(-tp.y, tp.x); res[j] += MAP.count(tp) ? MAP[tp] : 0; } } rep(i, 1, q) printf("%d\n", res[i]); }