Official

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: