A - Maxi-Buying Editorial by physics0523
この問題の本質は、整数に \(1.08\) を掛けて切り捨てるという操作です。
しかし、この処理を実数型の変数で行うのは、競技プログラミングにおいて計算誤差の原因となり危険です。
そこで、今回の問題では処理を整数型の変数のみで完結させることを考えます。
結論から言うと、 \(N\) に \(108\) を掛けてから、 \(100\) で割って小数点以下を切り捨てるという操作を行えばよいです。
この操作には、たいていのプログラミング言語の整数型で成り立つ以下の性質が利用できます。たとえば、 C++ の int 型における演算子 /
でこの性質が成り立ちます。
整数型同士の割り算の商をとる演算について、結果の整数部分が結果となり、小数点以下(余り)は切り捨てられる。
この方針で実装すると、次のようになります。
Rubyによる実装例:
input = gets.to_i
input = (input * 108) / 100
if input < 206 then
puts "Yay!\n"
elsif input == 206 then
puts "so-so\n"
else
puts ":(\n"
end
また、(誤差に注意しながら)実数型で演算を行って、切り捨てに相当する部分を条件分岐で処理することもできます。この解法が正当な理由は実装例の後に述べます。
Visual Basicによる実装例:
Module ABC206A
Sub Main()
Dim N As Double
N = Console.ReadLine()
N *= 1.08
If N < 206.0 Then
Console.WriteLine("Yay!")
ElseIf 206.0 <= N And N < 207.0
Console.WriteLine("so-so")
Else
Console.WriteLine(":(")
End If
End Sub
End Module
実は、以下の事項が成り立ちます。
- \(190 \times 1.08= 205.2\)
- \(191 \times 1.08 = 206.28\)
- \(192 \times 1.08 = 207.36\)
これらは、出力の境界値である整数から十分離れています。なので、今回の場合は誤差に注意しながら実数型で実装してもうまくいきます。 では、もっと簡単な方法はないでしょうか?
実は、この境界条件付近の \(3\) 式から、 \(N\le 190\) のとき Yay!
、 \(N=191\) のとき so-so
、 \(N \ge 192\) のとき :(
と出力すればいいことが分かります。
サンプル \(3\) がこの方針へのヒントになっていました。
Nimによる実装例:
import strutils
let n = stdin.readLine.parseInt
if n <= 190:
echo "Yay!\n"
elif n == 191:
echo "so-so\n"
else:
echo ":(\n"
posted:
last update: