コンテストURL: https://yukicoder.me/contests/567
解析コンテストから1年振りの単著コンです。今回は小数誤差コンテストで、広い意味で小数誤差に関わる問題を取り揃えさせていただきました。
ちなみに★2以下の問題に絞ってセットを組んだ都合、広い意味で小数誤差に関わる★2.5以上の問題がそこそこ余ってしまったので本当はエキストラコンテストも同時開催できたらいいなと思っていましたが、★2以下の10問のtesterさんを見つけるだけで残り1週間となってしまい★2.5以上のtesterさんを見つける時間は残っていなかったので諦めて1本に絞らせていただきました。
10問それぞれ小数誤差を扱う上でのポイント(攻略法)を決めて作問させていただきましたので、10問全部正解できれば★2以下で遭遇する小数誤差問題で気を付けるべきことの大部分は学べるんじゃないかなと思います。
解説にも色々と書かせていただいたので、解けた方もぜひ解説をお楽しみください。
それでは参加者の皆様、testerしてくださった方々、皆様ありがとうございました! なおリアクティブコンも準備中で、全問のtester作業が終わり次第また開催させていただきます。お楽しみに! アドベコンも$1$題出題予定です。★4のtesterさんを募集中なのでよろしくお願いいたします。
A: No.3352 中点判定 ★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3352 tester:yu23578さん | ||
小数誤差攻略法その1(小数誤差コンテストの各問題の解説に記載)割り算の式を掛け算の式に翻訳しましょう。 まずは★1の、プログラミング初心者向けの問題です。小数誤差うんぬんを学ぶための前提として、整数の範囲での割り算の理解を確認する問題です。 整数の型を使って整数の範囲で割り算を行うと当然有理数としての割り算とは別の値になってしまうことを理解できていれば、この問題は難なく解けるはずです。 | ||
B: No.3353 リウヴィルの定数計算 ★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3353 tester:Sinonenさん | ||
小数誤差攻略法その2(小数誤差コンテストの各問題の解説に記載)桁数の多い数は文字列で処理しましょう。 次に厳密な数値計算を行うための最も初歩的な方法の1つである、文字列を使った処理の理解を確認する問題です。 数値を文字列で管理する手法は桁数の大きい整数を扱う問題で頻出ですが、そういった問題は★1.5以上で主に出題されるため★1が適正な参加者にとっては初挑戦となると思います。 そこでこの問題は文字列として処理する以上のことは一切問わず、まずは文字列で数値を扱うことのみに慣れてもらうように作問させていただきました。 もちろん$1$が立つかどうかを場合分けで書いても実装は軽いので、お好きなようにお解きください。 | ||
C: No.3354 有理数の大小比較 ★☆ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3354 tester:yu23578さん | ||
小数誤差攻略法その3(小数誤差コンテストの各問題の解説に記載)有理数の比較は分母を払いましょう。 ここからは一段階難しくなって、少し考察が要求される★1.5の問題です。有理数を比較しようと思うと、すぐに思いつくのは小数型での比較です。しかし精度の足りない小数型を使ってしまうと比較が正しく行えないかもしれません。 そこで考察していただきたいのは、有理数の順序の(実数を用いない)定義です。実数の順序にも色々な定義がありますがその1つは有理数の順序を用いるものなので、当然ながら実数を用いずとも有理数の順序は定義されています。 具体的には正整数を両辺に書けることで分母を払って整数として大小比較するのが有理数の順序の定義の1つですね。この問題に限らず小数を使う問題はうまく整数に帰着させていきましょう。 | ||
D: No.3355 対数の整数部分 ★☆ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3355 tester:hamamuさん | ||
小数誤差攻略法その4(小数誤差コンテストの各問題の解説に記載)$n = \lfloor x \rfloor$ は $n \leq x < n+1$ に翻訳しましょう。 「実数$x$を超えない(以下である)最大の整数$n$」を「$x$の整数部分$n$」と捉えると、$n$の計算に$x$の厳密な計算が必要になったりして大変です。 代わりに「最大」の定義に戻って素直に「$n \leq x < n + 1$を満たす唯一の整数$n$」と捉えることで、不等式を変形して$n$を特徴づける良い関係式を得ることが可能です。 ついでにオーバーフローの要素も入れておきました。「float型でなくdouble型を使えば誤差を気にしなくて良くなる」という考え方が通用しないことを理解するためにも、「int型でなくlong long型を使えばオーバーフローを気にしなくて良くなる」という考え方が通用しないことをここで学んでいただきます。 | ||
E: No.3356 A÷B問題 ★☆ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3356 tester:hamamuさん | ||
小数誤差攻略法その5(小数誤差コンテストの各問題の解説に記載)小数展開は筆算で処理しましょう。 小数展開を求めるには、小数型で計算して出力するのが手っ取り早いです。しかしそういった方法にばかり慣れて、小学校で学んだ小数展開の方法を忘れてしまったらもったいないですよね。 既存の64bit整数型で扱えない128bitの掛け算が必要になったら128bit以上の整数型を使うか自分で筆算をで定義すれば良いことと同様に、64bitの小数型で扱えない128bit分の小数の割り算が必要になったら128bit以上の小数型を使うか自分で筆算を定義すれば良いわけです。 というわけで速解き勝負を銘打っておきながらしれっと重めの実装問題でした。実装をサボるためのテクニックや実装ミスを減らす工夫ができると乗り越えやすいですが、WAが出た時のデバッグは難しいかもしれません。 | ||
F: No.3357 eの部分和 mod 素数 ★★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3357 tester:yu23578さん | ||
小数誤差攻略法その6(小数誤差コンテストの各問題の解説に記載)法 $P$ の分数計算をライブラリー化しましょう。 ここからは競技プログラミング特有のテクニックが多く現れる、★2の問題です。先程も標準ライブラリにない機能は自分で実装していくと良いと述べましたが、競技プログラミングでは特に合同式を扱う型(通称modint型、mint型)を実装するかACLという有名ライブラリを借用する人が多いです。 ただライブラリー化することを促すだけの問題だとあまり理解せずに借用するだけで済んでしまい面白みに欠けると思ったので、本問では割り算の時間/空間計算量の理解を問うために制約を大きめにしてみました。 この問題は誤差を気にしないで済むように剰余を扱う問題なので自ずと誤差を気にしなくて済むわけですが、誤差を気にしなくても済むからといってそれはそれとして剰余を扱う時の注意点は色々あるのでそこを問おう、という流れでスパイスとして入れさせていただきました。 | ||
G: No.3358 逆数の小数部分 ★★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3358 tester:yu23578さん | ||
小数誤差攻略法その7(小数誤差コンテストの各問題の解説に記載)分数操作は分母分子の組の操作に翻訳しましょう。 有理数の操作を何度も繰り返す時、小数で扱うと一度の操作ならあまり誤差を気にしなくて良い状況でも操作を繰り返す間に誤差が致命的に広がってしまうかもしれません。 有理数を扱う方法は小数で扱う以外にも分数そのもの(分子と分母の組)として扱う方法があり、ここでもその方法で対処していきましょう。 なお分数そのものとして扱う方法は有理数に限らずmodint型でも有力です。ぜひ覚えておきましょう。 | ||
H: No.3359 ブリング根の3桁精度近似計算 ★★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3359 tester:hamamuさん | ||
小数誤差攻略法その8(小数誤差コンテストの各問題の解説に記載)有限小数計算は $10$ 冪を掛けて整数に翻訳しましょう。 $B$を$2$以上の整数として、$B$進法の有限小数を扱いたければ浮動小数点数の容量で「$B$を何回掛けるとどんな整数になるか」の2つのデータを持つとよいです。 つまりは $B$ をいっぱい掛けて整数にし、必要ならばleading zeroを補って、$B$を何回掛けたかを使って適切に小数点を打つということをすれば$B$進法の少数表示が可能というわけです。 | ||
I: No.3360 平方根の整数倍の整数部分 ★★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3360 tester:hamamuさん | ||
小数誤差攻略法その9(小数誤差コンテストの各問題の解説に記載)平方根の整数部分は二分探索しましょう。 小数に対する二分探索も可能ですが、小数誤差が心配です。厳密に解の範囲を求めたい時は整数の範囲での二分探索に帰着させていきましょう。 もちろん小数の代わりに分数を扱って二分探索しても構いません。二分探索は区間を縮めて行く操作ですが、その過程の区間は求めたい値の取りうる範囲を表すものなので、ある意味で精度保証付きの実数の精度を高くしていく操作とみなすことができます。 精度保証付きの実数同士の演算も実数と同様に定義され、それはまさに精度を表す区間の端点の演算で計算されるので区間演算とも呼ばれています。 何らかの実数を良い精度で求めたい時、そしてどの程度の精度になっているか確認したい時、区間演算を使っていきましょう。例えばテストケースを生成したい時に精度が分かると便利だったりするため、区間演算は作問にも役立ちます。 | ||
J: No.3361 2解間格子点 ★★ | ||
|---|---|---|
| 問題リンク:https://yukicoder.me/problems/no/3361 tester:loop0919さん | ||
小数誤差攻略法その10(小数誤差コンテストの各問題の解説に記載)実数の等式・不等式は整数の等式・不等式に変形しましょう。 ここまでで有理数や実数の等式・不等式を整数の等式・不等式に変形することを学びました。ただし変形前が1つの分数だったり1つの対数だったり1つの平方根だったりシンプルな等式・不等式ばかりだったので、最後に総集編として複合的な項が絡む複雑な不等式の変形を要求する問題を出題させていただきました。 分数と平方根の両方を解消しなければなりませんが、1つ1つの変形はこれまで学んできたことです。落ち着いて処理していきましょう。なおC問題では分母が正だったので分母を払う時に不等号が入れ替わりませんが、今回は分母が負になり得るので注意しましょう。 | ||