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减去情况三)

相关推荐
wutang0ka15 小时前
LeeCode HOT 100 104.二叉树的最大深度
算法
散峰而望15 小时前
【基础算法】从入门到实战:递归型枚举与回溯剪枝,暴力搜索的初级优化指南
数据结构·c++·后端·算法·机器学习·github·剪枝
setmoon21415 小时前
C++代码规范化工具
开发语言·c++·算法
进击的小头15 小时前
第15篇:MPC的发展方向及展望
python·算法
汉克老师15 小时前
GESP2026年3月认证C++三级( 第一部分选择题(9-15))
c++·字符串·数组长度·反码·枚举算法·gesp三级·gesp3级
We་ct15 小时前
LeetCode 35. 搜索插入位置:二分查找的经典应用
前端·算法·leetcode·typescript·个人开发
IT猿手15 小时前
基于 ZOH 离散化与增量 PID 的四旋翼无人机轨迹跟踪控制研究,MATLAB代码
开发语言·算法·matlab·无人机·动态路径规划·openclaw
A923A15 小时前
【洛谷刷题 | 第五天】
算法·字符串·递归·洛谷
就不掉头发15 小时前
C++右值与右值引用
开发语言·c++
炸膛坦客16 小时前
单片机/C/C++八股:(十六)C 中 malloc/free 和 C++ 中 new/delete 有什么区别?
c语言·开发语言·c++