AtCoder Beginner Contest 001

abc001.contest.atcoder.jp

www.slideshare.net

A - 積雪深差

h1 = gets.to_i
h2 = gets.to_i
puts h1 - h2

puts gets.to_i - gets.to_iでもよし。

B - 視程の通報

m = gets.to_i
if m < 100
  puts "00"
elsif m.between?(100, 5000)
  vv = m * 10 / 1000
  puts vv < 10 ? "0#{vv}" : vv
elsif m.between?(6000, 30000)
  puts m / 1000 + 50
elsif m.between?(35000, 70000)
  puts (m / 1000 - 30) / 5 + 80
elsif m > 70000
  puts 89
end
  • 2番目の条件節では、この後の問題Dでも使用するString#%を使ってもよかった
  • 最後のputs 89は、puts "89"の方が明確で一貫性があった
  • 8行目で「interpreted as grouped expression」と警告メッセージが出たので、putsの引数が長いときには、カッコを付けるか、変数に格納してから出力するべき

mをkmに変換するときに数値を浮動小数点数にするべきか迷ったが、この問題においては整数のままでも問題にならないので、整数のまま処理した。

C - 風力観測

class Float
  def direction
    degree_table = [11.25...33.75, 33.75...56.25, 56.25...78.75, 78.75...101.25,
                    101.25...123.75, 123.75...146.25, 146.25...168.75, 168.75...191.25,
                    191.25...213.75, 213.75...236.25, 236.25...258.75, 258.75...281.25,
                    281.25...303.75, 303.75...326.25, 326.25...348.75, 0.0..360.0]
    direction_table = %w(NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW N)
    degree_table.each_with_index do |direction, i|
      return direction_table[i] if direction.include? self
    end
  end
  
  def wind_force
    wind_table = [0.0..0.2, 0.3..1.5, 1.6..3.3, 3.4..5.4, 5.5..7.9,
                  8.0..10.7, 10.8..13.8, 13.9..17.1, 17.2..20.7, 20.8..24.4,
                  24.5..28.4, 28.5..32.6, 32.7..200.0]
    wind_table.each_with_index {|wind, i| return i if wind.include? self }
  end
end
 
# deg(整数)を引数に取ってdir(文字列)を返す
def deg_to_dir(deg)
  dir = (deg / 10.0).direction
end
 
# dis(整数)を引数に取ってw(整数)を返す
def dis_to_w(dis)
  w = (dis / 60.0).round(1).wind_force
end
 
deg, dis = gets.split.map(&:to_i)
dir = deg_to_dir(deg)
w = dis_to_w(dis)
dir = 'C' if w == 0
puts "#{dir} #{w}"
  • Float#directionにおけるブロック変数名directionが、メソッド名と同じなので変えるべき
  • deg_to_dirメソッド、dis_to_wメソッドは値を返すだけなので、わざわざ変数を用いる必要はない

D - 感雨時刻の整理

class Array
  def round
    s, e = self
    s -= s % 5 unless s % 5 == 0
    e += 5 - e % 5 unless e % 5 == 0
    e += 40 if e.to_s =~ /60\z/
    [s, e]
  end
  
  def merge
    return self if self.size <= 1
    (self.size - 1).times do |i|
      if self[i+1][0] <= self[i][1] && self[i][0] <= self[i+1][1]
        self[i+1] = [[self[i][0], self[i+1][0]].min, [self[i][1], self[i+1][1]].max]
        self[i] = nil
      end
    end
    self.compact
  end
end
 
n = gets.to_i
rainfall_times = []
n.times { rainfall_times << gets.split('-').map(&:to_i) }
rainfall_times.map(&:round).sort_by(&:first).merge.each do |rainfall_time|
  puts "%04d-%04d" % [rainfall_time[0], rainfall_time[1]]
end
  • 時間を丸めるために、分数が60になったときに40を足して処理するのは、機転が利いていてよかった
  • Array#roundにおけるいくつかのselfは省略できる(self.sizeself.compact

Array#mergeにおいてcompactではなくcompact!を使っていたことで、Runtime Errorを発生させてしまい、ドツボにはまった。

【参照】2つの期間が重なり合うかどうかを判定する。 - こせきの技術日記