BISHI86 圆覆盖¶
中等通过率 31.41%python3样例通过牛客 AC
一句话
以原点为心的圆,求覆盖权值和 >= S 的最小半径。
解题思路¶
这题考什么¶
「答案单调 -> 排序 + 前缀和」的经典套路。半径 r 越大覆盖的点越多、 权值和单调不减,所以答案具有单调性;而真正的最优半径一定恰好等于 某个点到原点的距离(再小就会丢掉那个点,再大是浪费)。
于是做法是:
- 对每个点算 d2 = x^2 + y^2(全程用整数平方,不开根,避免浮点误差);
- 按 d2 升序排序,求权值前缀和;
- 找到第一个前缀和 >= S 的位置 i,答案就是 sqrt(d2[i]); 若总权值和 < S,输出 -1。
第 3 步既可以 bisect 也可以线性扫,这里线性扫更直白。 前缀和的基本用法见 42-前缀和与差分。
数据规模与复杂度¶
n <= 1e5,排序 O(n log n),其余 O(n)。 S <= 1e14、v_i < 2^31 -> 权值和最大 1e5 * 2^31 ≈ 2e14,C++ 需要 long long, Python 天然大整数无需担心。
坑在哪¶
- 不要对 r 做实数二分再去数点——那是 O(n log(1/eps)),又慢又有精度问题; 排序法直接给出精确的 d2,只在最后开一次根号;
- x, y <= 1e9 -> d2 最大 2e18,超过 2^31 甚至接近 2^63, 必须用 64 位整数(Python 自动)。math.sqrt 接收这个大小的整数会转成 double, 相对误差约 1e-16,开根后仍远优于题目要求的 1e-6;
- v_i 可以是 0:权值为 0 的点不会成为「第一个使前缀和达标」的位置 (因为它不改变前缀和),所以不会导致答案偏大,逻辑天然正确;
- 无解时输出 -1(整数),不要输出 -1.000000 之外的奇怪格式; 有解时按题目允许 1e-6 相对误差,输出 6 位小数即可。
参考实现¶
[:octicons-arrow-left-16: BISHI85](BISHI85.md) [BISHI87 :octicons-arrow-right-16:](BISHI87.md)