JPRS编程竞赛2026#1(AtCoder初学者竞赛442)

题干

E - Laser Takahashi

AC代码概览

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
/*题目描述
https://atcoder.jp/contests/abc442/tasks/abc442_e
*/
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e5 + 5;

struct Node {
    int x, y, id, p;

    void cal_p() {
        if (!x)
            p = (y > 0) ? 0 : 4;
        else if (!y)
            p = (x > 0) ? 2 : 6;
        else if (x > 0 && y > 0)
            p = 1;
        else if (x > 0 && y < 0)
            p = 3;
        else if (x < 0 && y < 0)
            p = 5;
        else
            p = 7;
    }
} a[maxn];
int n, q, pos[maxn]; 
int pre[maxn], nxt[maxn];

bool cmp(Node a, Node b) {
    if (a.p != b.p)
        return a.p < b.p;
    int v1 = abs(a.y) * abs(b.x);
    int v2 = abs(b.y) * abs(a.x);
    if (a.p == 1 || a.p == 5)
        return v1 > v2;
    return v1 < v2;
}

int32_t main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].x >> a[i].y;
        a[i].id = i;
        a[i].cal_p();
    }
    sort(a + 1, a + n + 1, cmp);
    for (int i = 1; i <= n; i++) {
        pos[a[i].id] = i;
        if (i > 1 && a[i].p == a[i - 1].p 
                  && a[i].y * a[i - 1].x == a[i - 1].y * a[i].x)
            pre[i] = pre[i - 1];
        else
            pre[i] = i;
    }
    for (int i = n; i >= 1; i--) {
        if (i < n && a[i].p == a[i + 1].p 
                  && a[i].y * a[i + 1].x == a[i + 1].y * a[i].x)
            nxt[i] = nxt[i + 1];
        else
            nxt[i] = i;
    }
    for (int i = 0, a, b, ans; i < q; i++) {
        cin >> a >> b;
        a = pos[a];
        b = pos[b];
        if (pre[a] == pre[b] || a < b)
            ans = nxt[b] - pre[a] + 1;
        else
            ans = nxt[b] + n - pre[a] + 1;
        cout << ans << endl;
    }
    return 0;
}

逐段解析一

cpp 复制代码
struct Node {
    int x, y, id, p;

    void cal_p() {
        if (!x)
            p = (y > 0) ? 0 : 4;
        else if (!y)
            p = (x > 0) ? 2 : 6;
        else if (x > 0 && y > 0)
            p = 1;
        else if (x > 0 && y < 0)
            p = 3;
        else if (x < 0 && y < 0)
            p = 5;
        else
            p = 7;
    }
} a[maxn];

我们将一个坐标系划分成8个部分其中0,2,4,6是坐标轴,1,3,5,7是四象限

cpp 复制代码
bool cmp(Node a, Node b) {
    if (a.p != b.p)
        return a.p < b.p;
    int v1 = abs(a.y) * abs(b.x);
    int v2 = abs(b.y) * abs(a.x);
    if (a.p == 1 || a.p == 5)
        return v1 > v2;
    return v1 < v2;
}
...
sort(a + 1, a + n + 1, cmp);

这里的比较函数首先通过八个部分进行比较,接着在相同部分的情况下,通过斜率进行比较,之所以不用角度或者弧度进行比较是因为后者涉及到小数比较不够精准也不够方便,但是同过斜率的不等式我们很容易得到"乘式",也就是说只需要进行整数之间的比较。这样做的本质原因是题目中要求顺时针,再加上数据量足够我们进行nlog(n)的遍历,所以我们有必要先对所有坐标进行一个顺时针的排序

逐段解析二

cpp 复制代码
    for (int i = 1; i <= n; i++) {
        pos[a[i].id] = i;
        if (i > 1 && a[i].p == a[i - 1].p 
                  && a[i].y * a[i - 1].x == a[i - 1].y * a[i].x)
            pre[i] = pre[i - 1];
        else
            pre[i] = i;
    }
    for (int i = n; i >= 1; i--) {
        if (i < n && a[i].p == a[i + 1].p 
                  && a[i].y * a[i + 1].x == a[i + 1].y * a[i].x)
            nxt[i] = nxt[i + 1];
        else
            nxt[i] = i;
    }

1, pos[a[i].id] = i;

这一段是为了给排好序的a[i]中的每个坐标给他们标好rank,至此排序结束。

2,其余部分是 为了解决题目中所提到的可能出现在同一射线上的点,也就是在进行区间统计时如果不进行适当的操作会造成边界部分损失的问题,本质上是没有定义适当的边界,那么我们通过向前遍历所有的点可以找出在同一条射线上的点并将他们分组,这个组是前边沿组,也就是这个组的值是最前边沿的点的编号,同理通过向前遍历所有的点我们可以的到末边沿的组,这个组的值是最末边沿的点的编号。这样以来我们就可以确定最适当的边沿(最大区间,避免损失)。

逐段解析三

cpp 复制代码
for (int i = 0, a, b, ans; i < q; i++) {
        cin >> a >> b;
        a = pos[a];
        b = pos[b];
        if (pre[a] == pre[b] || a < b)
            ans = nxt[b] - pre[a] + 1;
        else
            ans = nxt[b] + n - pre[a] + 1;
        cout << ans << endl;
    }

最后一部分也就是输出部分,根据每个查询给出的两个坐标编号,我们先确定他们在顺时针中的实际顺序:
cin >> a >> b;
a = pos[a];
b = pos[b];

接下来我们需要确定他们的位置关系:

1,在一条射线上

2,左小右大

3,右小左大

其中1,2情况处理方法一致,只需要大减小得出中间右多少个

第三个情况需要先用2的方法做再加个n(可以看成用n减去情况三)

相关推荐
你撅嘴真丑11 小时前
第九章-数字三角形
算法
在路上看风景11 小时前
19. 成员初始化列表和初始化对象
c++
uesowys11 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
zmzb010311 小时前
C++课后习题训练记录Day98
开发语言·c++
ValhallaCoder11 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮11 小时前
AI 视觉连载1:像素
算法
念风零壹12 小时前
C++ 内存避坑指南:如何用移动语义和智能指针解决“深拷贝”与“内存泄漏”
c++
智驱力人工智能12 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
孞㐑¥13 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
月挽清风13 小时前
代码随想录第十五天
数据结构·算法·leetcode