H - Takahashi is Slime 2 Editorial by kyopro_friends

誤差について

after_contestケースが追加され、吸収できるかどうかの判定を倍精度浮動小数点数型(c++ならdouble、pythonならfloat、rustならf64、etc)で行う解法がWAになるようになりました。

if (吸収したいスライムの大きさ) < (高橋君の大きさ)/X:
    吸収する

具体的には、以下のとき、浮動小数点数の丸め誤差の影響により判定に失敗します。

  • \(X=2^{14}=16384\)
  • 吸収したいスライムの大きさが \(2^{39}=549755813888\)
  • 高橋君の大きさが \(2^{53}+1=9007199254740993\)

どうすればよいか

案1

\(X\) を移項し、

slime_size * X < takahashi_size

とすることで整数演算で判定することができます。ただし、左辺は \(2^{64}\) 以上の値を取りうるため、オーバーフローに注意する必要があります。(128bit整数や多倍長整数を使うほか、一旦doubleで乗算を計算して \(2^{60}\) 程度以上かどうかで場合分けするなどの方法があります)

案2

  • \(n\) を整数、\(\alpha\) を実数とするとき、\(n < \alpha \Longleftrightarrow n < \lceil\alpha\rceil\) が成り立つ
  • \(a\) を整数、\(b\) を正整数とするとき、 \(\displaystyle \left\lceil\frac{a}{b}\right\rceil =\left\lfloor\frac{a+b-1}{b}\right\rfloor\) が成り立つ

この2つの性質を使うことで、

slime_size < (takahashi_size + X-1) / X

のように整数演算で不等式部分の計算を行うことができます。(整数除算は切り捨てになると暗黙的に仮定しています)

公式解説のコードもこのように書かれています(37行目)

posted:
last update: