UVa 1325 Hypertransmission

题目描述

银河联邦有 NNN 个行星,每个行星有三维坐标 (xi,yi,zi)(x_i, y_i, z_i)(xi,yi,zi) 和所属政治派别 pi∈{0,1}p_i \in \{0, 1\}pi{0,1}000 代表工业主义,111 代表生态主义)。联邦计划在每个行星上建立超广播发射机,所有发射机具有相同的覆盖半径 RRR。接收规则如下:

  • 行星 AAA 的广播可以被所有与其欧几里得距离 ≤R\le RR 的行星接收(包括自身)。
  • N+(A)N^+(A)N+(A) 表示与 AAA 政治派别相同且能接收到 AAA 广播的行星数量。
  • N−(A)N^-(A)N(A) 表示与 AAA 政治派别不同且能接收到 AAA 广播的行星数量。

N+(A)<N−(A)N^+(A) < N^-(A)N+(A)<N(A),则称行星 AAA不稳定行星

你的任务是:

  1. 选择半径 R≥0R \ge 0R0,使得不稳定行星的数量 DDD 最大。
  2. 在满足 DDD 最大的前提下,选择最小的 RRR
  3. 对每组数据输出最大不稳定行星数 DDD 及对应的最小 RRR(精度 10−410^{-4}104)。

输入格式

多组数据。每组数据第一行为整数 NNN1≤N≤10001 \le N \le 10001N1000)。接下来 NNN 行,每行四个整数 xi,yi,zi,pix_i, y_i, z_i, p_ixi,yi,zi,pi,坐标绝对值不超过 100001000010000,保证没有两个行星坐标完全相同。

输出格式

每组数据输出两行:第一行是最大不稳定行星数 DDD,第二行是最小半径 RRR(保留四位小数)。

题目分析

基本性质

  • R=0R = 0R=0 时,每个行星只能收到自己的广播,因此 N+=1N^+ = 1N+=1N−=0N^- = 0N=0,没有行星不稳定(1<01 < 01<0 不成立),D=0D = 0D=0
  • 随着 RRR 增大,每个行星能够接收到的其他行星越来越多。当 RRR 足够大时,所有行星都能接收到所有其他行星的广播,此时 N+N^+N+ 为与该行星相同派别的总行星数,N−N^-N 为不同派别的总行星数。如果某个行星属于少数派,它可能变得不稳定。
  • N+N^+N+N−N^-N 只在 RRR 经过某两个行星之间的距离时才会发生变化(增加一个行星)。因此,候选 RRR 只能是 000 或某对行星之间的距离。
  • 最大 NNN100010001000,行星对的数量约为 5×1055 \times 10^55×105,可以在 O(N2)O(N^2)O(N2) 时间内枚举并排序。

朴素算法与复杂度瓶颈

朴素的思路是:枚举所有候选 RRR,对每个 RRR 计算所有行星的 N+N^+N+N−N^-N,统计不稳定行星数。每个 RRR 需要 O(N2)O(N^2)O(N2) 时间,候选 RRRO(N2)O(N^2)O(N2) 个,总复杂度 O(N4)O(N^4)O(N4),对于 N=1000N=1000N=1000 完全不可接受。

我们需要一个能够 增量更新 的算法,使得当 RRR 逐渐增大时,用 O(1)O(1)O(1)O(log⁡N)O(\log N)O(logN) 的时间处理每个距离事件。

解题思路

核心思想:事件驱动 + 滑动窗口

我们可以将 RRR000 开始逐渐增大。当 RRR 经过某两个行星 iiijjj 之间的距离时,它们彼此之间刚刚进入对方的接收范围。此时:

  • 对于行星 iii:如果 pi=pjp_i = p_jpi=pj,则 N+(i)N^+(i)N+(i) 增加 111;否则 N−(i)N^-(i)N(i) 增加 111
  • 对于行星 jjj:如果 pi=pjp_i = p_jpi=pj,则 N+(j)N^+(j)N+(j) 增加 111;否则 N−(j)N^-(j)N(j) 增加 111

换句话说,每个行星对 (i,j)(i, j)(i,j) 产生一个 事件,事件的距离为它们的欧几里得距离。当处理到这个事件时,需要同时更新两个行星的计数。

维护不稳定行星数

我们维护两个数组:

  • sameCount[k]:行星 kkk 当前 N+N^+N+ 值(包括自身)。
  • diffCount[k]:行星 kkk 当前 N−N^-N 值。

以及一个布尔数组 isUnstable[k] 标记行星 kkk 当前是否不稳定。

全局变量 curD 记录当前 RRR 下的不稳定行星总数。

初始状态 R=0R = 0R=0,每个行星只能收到自己:

  • sameCount[k] = 1
  • diffCount[k] = 0
  • 没有行星不稳定,curD = 0
  • 初始最优解 bestD = 0bestR = 0

事件排序与批量处理

由于可能存在多个行星对距离相等的情况,我们需要将这些距离相同的事件 批量处理。处理一批事件时,先应用该批次中所有事件的增量和减量,然后再判断是否有新的最优解。这样可以保证对于同一个 RRR,所有变化都已被计入。

复杂度分析

  • 计算所有距离:O(N2)O(N^2)O(N2)
  • 存储所有事件:O(N2)O(N^2)O(N2) 个事件,每个事件包含距离和两个行星的索引以及类型。
  • 排序事件:O(N2log⁡N)O(N^2 \log N)O(N2logN),对于 N=1000N=1000N=1000 约为 5×105×20≈1075 \times 10^5 \times 20 \approx 10^75×105×20107 次比较,可以接受。
  • 扫描事件:每个事件被处理一次,每次更新两个行星的状态(O(1)O(1)O(1)),总 O(N2)O(N^2)O(N2)
  • 总复杂度 O(N2log⁡N)O(N^2 \log N)O(N2logN),满足时间限制(666 秒)。

细节注意

  1. 浮点数精度:判断两个距离是否相等时,需要使用容差比较,例如 fabs(a - b) < 1e-9。但在排序和扫描事件时,我们直接使用 < 排序,然后通过 fabs 判断是否属于同一批次。
  2. 自身计数:初始时 sameCount 包含自身,这样当处理行星对事件时,更新的都是其他行星,无需特殊处理。
  3. 相同距离的批量处理:在扫描事件时,先用一个循环收集所有距离为 curDist 的事件,然后统一更新。这样可以避免因更新顺序不同导致的不一致。
  4. 最优解更新时机:在每一批事件全部处理完毕后,再判断 curD 是否大于 bestD。这样保证对于某个距离 RRR,我们计算的是 RRR 刚好包含所有距离 ≤R\le RR 的行星时的状态。

代码实现

// Hypertransmission
// UVa ID: 1325
// Verdict: Accepted
// Submission Date: 2026-04-25
// UVa Run Time: 0.360s
//
// 版权所有(C)2026,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

struct Planet {
    int x, y, z, p;
};

struct Event {
    double dist;
    int a, b;      // 行星对 (a, b),a < b
    int type;      // 0: 派别相同,1: 派别不同
};

bool eventLess(const Event& e1, const Event& e2) {
    return e1.dist < e2.dist;
}

void solve(int N, vector<Planet>& planets) {
    vector<Event> events;

    // 生成所有行星对事件
    for (int i = 0; i < N; ++i) {
        for (int j = i + 1; j < N; ++j) {
            long long dx = planets[i].x - planets[j].x;
            long long dy = planets[i].y - planets[j].y;
            long long dz = planets[i].z - planets[j].z;
            double d = sqrt(dx * dx + dy * dy + dz * dz);
            if (planets[i].p == planets[j].p) {
                events.push_back({d, i, j, 0}); // 相同派别
            } else {
                events.push_back({d, i, j, 1}); // 不同派别
            }
        }
    }
    sort(events.begin(), events.end(), eventLess);

    // 初始状态 R = 0,每个行星只能收到自己
    vector<int> sameCount(N, 1);   // 包括自身
    vector<int> diffCount(N, 0);
    vector<bool> isUnstable(N, false);
    int curD = 0;

    for (int i = 0; i < N; ++i) {
        if (sameCount[i] < diffCount[i]) {
            isUnstable[i] = true;
            curD++;
        }
    }

    int bestD = curD;
    double bestR = 0.0;

    size_t idx = 0;
    while (idx < events.size()) {
        double curDist = events[idx].dist;
        vector<Event> batch;
        // 收集所有距离为 curDist 的事件(容差 1e-9)
        while (idx < events.size() && fabs(events[idx].dist - curDist) < 1e-9) {
            batch.push_back(events[idx]);
            idx++;
        }

        // 应用这批事件,更新计数
        for (const Event& e : batch) {
            // 更新行星 a
            bool wasUnstableA = isUnstable[e.a];
            if (e.type == 0) {
                sameCount[e.a]++;
            } else {
                diffCount[e.a]++;
            }
            bool nowUnstableA = (sameCount[e.a] < diffCount[e.a]);
            if (wasUnstableA && !nowUnstableA) curD--;
            else if (!wasUnstableA && nowUnstableA) curD++;
            isUnstable[e.a] = nowUnstableA;

            // 更新行星 b
            bool wasUnstableB = isUnstable[e.b];
            if (e.type == 0) {
                sameCount[e.b]++;
            } else {
                diffCount[e.b]++;
            }
            bool nowUnstableB = (sameCount[e.b] < diffCount[e.b]);
            if (wasUnstableB && !nowUnstableB) curD--;
            else if (!wasUnstableB && nowUnstableB) curD++;
            isUnstable[e.b] = nowUnstableB;
        }

        // 更新最优解
        if (curD > bestD) {
            bestD = curD;
            bestR = curDist;
        }
    }

    printf("%d\n%.4lf\n", bestD, bestR);
}

int main() {
    int N;
    while (scanf("%d", &N) == 1) {
        vector<Planet> planets(N);
        for (int i = 0; i < N; ++i) {
            scanf("%d%d%d%d", &planets[i].x, &planets[i].y, &planets[i].z, &planets[i].p);
        }
        solve(N, planets);
    }
    return 0;
}

总结

本题的核心在于:

  • 认识到候选 RRR 只能是 000 或某对行星之间的距离,从而将连续优化问题转化为离散事件处理问题。
  • 使用事件驱动的方法,将 O(N4)O(N^4)O(N4) 的朴素算法优化到 O(N2log⁡N)O(N^2 \log N)O(N2logN)
  • 通过批量处理相同距离的事件,避免了浮点数精度问题带来的顺序歧义。
  • 维护全局不稳定计数,使得每次事件更新只需 O(1)O(1)O(1) 时间。

这种 事件扫描 + 增量更新 的技巧在很多几何问题和距离阈值问题中都有广泛应用,值得熟练掌握。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值