🙌

ABC191 D - Circle Lattice Points

2021/02/14に公開

問題概要

中心(X, Y)、半径Rの円の内部および円周上にある格子点の数を求めよ

解法

求める格子点を(x, y)とおく
まずxとして考えられる範囲を求める
xは円の中心からRの距離の範囲にあるので、

X - R \le x \le X + R

xは整数であるので

\lfloor X - R \rfloor \le x \le \lceil X + R \rceil

そして、xが決まればyの範囲も決まる

上図において、三平方の定理より

R^2 = (X-x)^2 + y^2 \tag{1}

が成り立ち、これからyの範囲を決めることができる

この問題では、X, Y, Rが小数点以下4桁までの小数として与えられており、
愚直に計算すると誤差が問題になる
まずX, Y, Rを1000倍して、整数にする
この計算においても受け取った数を浮動小数点数として表す際の誤差、
1000倍する際の誤差が問題になるため注意する必要がある
roundなどを使って丸めることで誤差の影響を無視することができる

求める格子点の個数は中心(1000X, 1000Y)、半径1000Rの円の内部および円周上にある、(x, y)が共に1000の倍数であるような点の個数に等しい
まずxの範囲を求める
x = 1000iと置くと

1000X - 1000R \le 1000i \le 1000x + 1000R
\lfloor \frac{1000X - 1000R}{1000} \rfloor \le i \le \lceil \frac{1000X + 1000R}{1000} \rceil

そしてyの範囲を決めるときにそのまま(1)式から

y = \sqrt{R^2 - (X-x)^2}

としてしまうと、平方根の計算で浮動小数点数が出てきてしまう
(1)式に対して、

R^2 \ge (X-x)^2 + y^2

という条件を考えると、これは単調性をもち、
二分探索によって、この条件をみたす最大の整数yを求める事ができる
その整数値をy'とすると、-y'以上、y'以下の1000の倍数の個数が答えになる
y = 1000jとすると

-y' \le 1000j \le y'
\lfloor \frac{-y'}{1000} \rfloor \le j \le \lceil \frac{y'}{1000} \rceil

つまり\lceil \frac{y'}{1000} \rceil - \lfloor \frac{-y'}{1000} \rfloor + 1個存在する
iについて、この個数を答えに加算していく

提出コード

https://atcoder.jp/contests/abc191/submissions/20033259

Discussion