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, posa\[i.id] = i;

这一段是为了给排好序的ai中的每个坐标给他们标好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 = posa;
b = posb;

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

1,在一条射线上

2,左小右大

3,右小左大

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

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

相关推荐
GreatSQL社区12 分钟前
主从复制SQL线程中断——字符集砸出的坑
java·数据库·算法
ZZHow10241 小时前
Ascend C算子开发(高级)笔记
c++·人工智能·笔记·深度学习·华为云
Tisfy1 小时前
LeetCode 2333.最小差值平方和:排序 + 数学计算(不用二分)
数学·算法·leetcode·题解·贪心·排序
aqiu1111111 小时前
【C++算法打怪专栏】LeetCode 217. 存在重复元素(解法总结)
c++·算法·leetcode
lojox2 小时前
深入理解 C++ STL:vector 底层实现、迭代器失效与 list 特性
开发语言·c++
微笑星河q2 小时前
C++类和对象(下)初始化列表、类型转换、static、友元、内部类、匿名对象
开发语言·c++
yi0113 小时前
DAY28: LeetCode 111. 二叉树的最小深度
人工智能·笔记·python·算法·leetcode·二叉树·递归
|_⊙3 小时前
C++ 类和对象零散知识点
开发语言·c++
wuyk5553 小时前
27.LeetCode 2265. 统计值等于子树平均值的节点数 —— 后序遍历实战
stm32·单片机·嵌入式硬件·算法
xiangyun613 小时前
C++ list 模拟实现(二):const迭代器与反向迭代器,模板的黑魔法
开发语言·数据库·c++·算法·stl·list