{ }codelper
累乗平方根オーバーフローP0129

スプリンクラーが届く鉢

庭にスプリンクラーが一つと植木鉢が n 個ある。
一行目にスプリンクラーの位置 x0, y0 と、水が届く半径 r が与えられる。
二行目に鉢の数 n が与えられ、続く n 行に鉢の位置 x, y が一つずつ与えられる。
スプリンクラーと鉢の間の(直線)距離が r 以下なら、その鉢は水を受ける。
一行目に水を受ける鉢の数を出力せよ。
二行目に、r 以上の整数のうち、半径にするとすべての鉢が水を受ける最小のものを出力せよ(半径は小さくしない)。
したがって、すでにすべての鉢が水を受けていれば r をそのまま出力する。

入力
座標はすべて -100000 以上 100000 以下の整数、0 ≤ r ≤ 300000、1 ≤ n ≤ 1000
出力
二行:水を受ける鉢の数、r 以上で必要な最小の整数半径
例 1 · stdin
0 0 5
4
3 4
6 0
-1 -1
0 -7
stdout
2
7
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

距離は √(dx² + dy²) ですが、二乗のまま dx² + dy² <= r² を比べれば整数だけで正確です。
落とし穴は二乗の大きさです。
座標の差は 20 万まであるので距離の二乗は 8×10^10 まで大きくなり、32 ビット int(約 21 億)を超えます。
Java・C# は long、C・C++ は long long で計算する必要があり、int だと黙ってあふれておかしな値になります。
Python の整数には大きさの制限がなく、JS・TS・Craykon の数は 2^53 まで整数が正確なので、この範囲では大丈夫です。
累乗は Python・JS・TS **、Java・C# Math.pow/Math.Pow、C pow、C++ std::pow で、後ろの四つは実数(double)を返します。
Craykon には累乗の演算子がないので dx * dx と書きます。
二乗は dx * dx がいちばん簡単で正確です。
C・C++・Java・C#・JS・TS・Python で dx ^ 2 は累乗ではなくビット XOR なので、エラーなしに誤った値になります。
二行目は、最も遠い距離の二乗 D について √D を切り上げた値です。
Python は math.isqrt で整数の平方根をそのまま得られ、他の言語は sqrt で見積もってから s * s と D を比べて直し、切り上げる習慣が安全です(この範囲では double の平方根で正しいですが、もっと大きな数では一つずれることがあります)。
平方根は Python math.sqrt、JS・TS Math.sqrt、Java Math.sqrt、C# Math.Sqrt、C sqrt(<math.h>)、C++ std::sqrt、Craykon 数学.平方根 です。
切り下げた平方根を切り上げずに使うと、半径が 1 足りなくなります。

Pythonmain.py · 17 行
import math x0, y0, r = map(int, input().split())n = int(input())watered = 0far = 0  # 가장 먼 화분까지 거리의 제곱for _ in range(n):    x, y = map(int, input().split())    d2 = (x - x0) ** 2 + (y - y0) ** 2  # 제곱끼리 비교하면 정수만으로 정확하다    if d2 <= r ** 2:        watered += 1    far = max(far, d2)s = math.isqrt(far)  # 정수 제곱근(내림)if s * s < far:    s += 1  # 올림print(watered)print(max(r, s))
JavaScriptmain.js · 13 行
const [x0, y0, r, n, ...pts] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let watered = 0;let far = 0; // 가장 먼 화분까지 거리의 제곱for (let i = 0; i < n; i++) {  const d2 = (pts[2 * i] - x0) ** 2 + (pts[2 * i + 1] - y0) ** 2; // 8×10^10 이하라 number로 정확하다  if (d2 <= r ** 2) watered++;  far = Math.max(far, d2);}let s = Math.floor(Math.sqrt(far));while (s * s > far) s--; // 실수 제곱근이 한 칸 어긋나도 바로잡는다while ((s + 1) * (s + 1) <= far) s++;if (s * s < far) s++; // 올림console.log(watered + "\n" + Math.max(r, s));
TypeScriptmain.ts · 14 行
import { readFileSync } from "node:fs";const [x0, y0, r, n, ...pts]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let watered = 0;let far = 0; // 가장 먼 화분까지 거리의 제곱for (let i = 0; i < n; i++) {  const d2: number = (pts[2 * i] - x0) ** 2 + (pts[2 * i + 1] - y0) ** 2; // 8×10^10 이하라 number로 정확하다  if (d2 <= r ** 2) watered++;  far = Math.max(far, d2);}let s: number = Math.floor(Math.sqrt(far));while (s * s > far) s--; // 실수 제곱근이 한 칸 어긋나도 바로잡는다while ((s + 1) * (s + 1) <= far) s++;if (s * s < far) s++; // 올림console.log(watered + "\n" + Math.max(r, s));
JavaMain.java · 23 行
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        long x0 = sc.nextLong(), y0 = sc.nextLong(), r = sc.nextLong();        int n = sc.nextInt();        int watered = 0;        long far = 0; // 가장 먼 화분까지 거리의 제곱        for (int i = 0; i < n; i++) {            long dx = sc.nextLong() - x0, dy = sc.nextLong() - y0;            long d2 = dx * dx + dy * dy; // long이라야 넘치지 않는다(최대 8×10^10)            if (d2 <= r * r) watered++;            far = Math.max(far, d2);        }        long s = (long) Math.sqrt(far);        while (s * s > far) s--; // 실수 제곱근이 한 칸 어긋나도 바로잡는다        while ((s + 1) * (s + 1) <= far) s++;        if (s * s < far) s++; // 올림        System.out.println(watered);        System.out.println(Math.max(r, s));    }}
C#Main.cs · 28 行
using System;using System.Linq; class Program{    static void Main()    {        long[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray();        long x0 = first[0], y0 = first[1], r = first[2];        int n = int.Parse(Console.ReadLine());        int watered = 0;        long far = 0; // 가장 먼 화분까지 거리의 제곱        for (int i = 0; i < n; i++)        {            long[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray();            long dx = p[0] - x0, dy = p[1] - y0;            long d2 = dx * dx + dy * dy; // long이라야 넘치지 않는다(최대 8×10^10)            if (d2 <= r * r) watered++;            far = Math.Max(far, d2);        }        long s = (long)Math.Sqrt(far);        while (s * s > far) s--; // 실수 제곱근이 한 칸 어긋나도 바로잡는다        while ((s + 1) * (s + 1) <= far) s++;        if (s * s < far) s++; // 올림        Console.WriteLine(watered);        Console.WriteLine(Math.Max(r, s));    }}
C++main.cpp · 24 行
#include <algorithm>#include <cmath>#include <iostream> int main() {    long long x0, y0, r;    int n;    std::cin >> x0 >> y0 >> r >> n;    int watered = 0;    long long far = 0; // 가장 먼 화분까지 거리의 제곱    for (int i = 0; i < n; i++) {        long long x, y;        std::cin >> x >> y;        long long dx = x - x0, dy = y - y0;        long long d2 = dx * dx + dy * dy; // long long이라야 넘치지 않는다(최대 8×10^10)        if (d2 <= r * r) watered++;        far = std::max(far, d2);    }    long long s = static_cast<long long>(std::sqrt(static_cast<double>(far)));    while (s * s > far) s--; // 실수 제곱근이 한 칸 어긋나도 바로잡는다    while ((s + 1) * (s + 1) <= far) s++;    if (s * s < far) s++; // 올림    std::cout << watered << '\n' << std::max(r, s) << '\n';}
Cmain.c · 24 行
#include <math.h>#include <stdio.h> int main(void) {    long long x0, y0, r;    int n;    scanf("%lld %lld %lld %d", &x0, &y0, &r, &n);    int watered = 0;    long long far = 0; // 가장 먼 화분까지 거리의 제곱    for (int i = 0; i < n; i++) {        long long x, y;        scanf("%lld %lld", &x, &y);        long long dx = x - x0, dy = y - y0;        long long d2 = dx * dx + dy * dy; // long long이라야 넘치지 않는다(최대 8×10^10)        if (d2 <= r * r) watered++;        if (d2 > far) far = d2;    }    long long s = (long long)sqrt((double)far);    while (s * s > far) s--; // 실수 제곱근이 한 칸 어긋나도 바로잡는다    while ((s + 1) * (s + 1) <= far) s++;    if (s * s < far) s++; // 올림    printf("%d\n%lld\n", watered, s > r ? s : r);    return 0;}
Craykonmain.cray · 34 行
first = コンソール.数読み();x0 = first[0];y0 = first[1];r = first[2];n = コンソール.行読み().数に();watered = 0;far = 0; // 가장 먼 화분까지 거리의 제곱繰り返す (i = 0; i < n; i++){    p = コンソール.数読み();    dx = p[0] - x0;    dy = p[1] - y0;    d2 = dx * dx + dy * dy; // 거듭제곱 연산자가 없으니 곱해서 제곱한다    もし (d2 <= r * r)    {        watered += 1;    }    far = 数学.大きい方(far, d2);}s = 数学.切り下げ(数学.平方根(far));間 (s * s > far){    s -= 1; // 실수 제곱근이 한 칸 어긋나도 바로잡는다}間 ((s + 1) * (s + 1) <= far){    s += 1;}もし (s * s < far){    s += 1; // 올림}コンソール.書く(watered);コンソール.書く(数学.大きい方(r, s));