ccpc题解java,Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解(示例代码)

题意:给定二维平面上的(n)个点,(q)次询问,每次加入一个点,询问平面上有几个包含该点的直角三角形。

分析:这是一篇鸽了很久的题解,主要原因就是现场赛的时候这题惨遭卡常,锅++。现在回过头来想这题,主要问题出在现场赛时误判了(map)的时间复杂度,把极角排序的正确想法成功叉掉,以及现场赛时候的共线计数使用了(gcd),使得整体复杂度上升。(但还是有大佬拿gcd思想过了,我太菜了)现在学了一种共线计数的新想法,只需要重载就能实现,于是再用(map)来写一写这道题。。。

本题思路不难,将直角三角形分为两类,一类是以新加入点为直角顶点的直角三角形,另一类新加入点不作直角顶点。第一种情况,我们将新加入点与原有点之间构成的所有向量加入(map),然后通过点积为零的性质查找垂直的向量个数。(会计数两次,要除以二)另一类采取离线操作,我们将每个原有点当作直角顶点遍历,并将该点与另外原有点构成的向量加入(map),更新(q)个新加入点的直角三角形数量即可。

AC代码:

#pragma GCC target("avx")

#pragma GCC optimize(3)

#pragma GCC optimize("Ofast")

#include

#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

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 MAP;

int main() {

scanf("%d %d", &n, &q);

int m = q;

vector vec(q + 1);

vector 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

", res[i]);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值