Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解

题目链接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]);
}
posted @ 2019-10-13 00:01  st1vdy  阅读(482)  评论(1编辑  收藏  举报