AtCoder/ABC138

https://atcoder.jp/contests/abc138

A - Red or Not

puts (gets.to_i >= 3200) ? gets.chomp : "red"

 

B - Resistors in Parallel

gets
as = gets.split.map(&:to_i)

puts Rational(1, as.map {|i| Rational(1, i)}.inject(:+)).to_f

 

C - Alchemist

gets
as = gets.split.map(&:to_i).sort

def calc(ary)
  return ary.first if ary.size == 1
  a = Rational(ary[0] + ary[1], 2)
  calc([a] + ary[2..-1])
end

puts calc(as).to_f

いや、これわからんよ。思いつかないし。
 

D - Ki

n, q = gets.split.map(&:to_i)

#頂点 a と b を結ぶ
tree = Array.new(n + 1) {[]}
(n - 1).times do
  a, b = gets.split.map(&:to_i)
  tree[a] << b
  tree[b] << a
end

#頂点 p は根で、部分木のすべての頂点に足されるのは x
total = Array.new(n + 1, 0)
q.times do
  p, x = gets.split.map(&:to_i)
  total[p] += x
end

#実際に足す操作
visited = Array.new(n + 1)
queue = [1]
until queue.empty?
  c = queue.shift
  visited[c] = true
  tree[c].each do |q|
    next if visited[q]
    total[q] += total[c]
    queue << q
  end
end
 
puts total[1..n].join(" ")

RE はスタックオーバーフローになっていたみたいだ。

ある双曲線の整数解

36*x^2-4*x-71*y^2+8=0 の整数解の導出。

Ruby でできるだけ解いてみる。
solve.rb

dir = [[1, 0], [0, 1], [-1, 0], [0, -1]]

x = y = 0
step = 1
f = ->{p [x, y] if 36 * x ** 2 - 4 * x - 71 * y ** 2 + 8 == 0}
add = ->(i) {
  dx, dy = dir[i]
  x += dx
  y += dy
}

loop do
  2.times do |j|
    step.times do
      f.()
      add.(j * 2)
    end
    step.times do
      f.()
      add.(j * 2 + 1)
    end
    step += 1
  end
end

 
実行。

$ ruby solve.rb
[-1629, 1160]
[-1629, -1160]

これしか見つかっていない。

AtCoder/ABC137

A - +-x

a, b = gets.split.map(&:to_i)
puts [a + b, a - b, a * b].max

 

B - One Clue

k, x = gets.split.map(&:to_i)
puts [*x - k + 1..x + k - 1].join(" ")

 

C - Green Bin

words = gets.to_i.times.map {gets.chomp.chars.sort.join}.group_by(&:itself)
ans = words.inject(0) do |acc, (_, ary)|
  l = ary.size
  l == 1 ? acc : acc + l * (l - 1) / 2
end
puts ans

これは他の人の回答を見た。
あとで自分で考えたもの。

table = {}
count = 0
 
gets.to_i.times.map {gets.chomp.chars.sort}.each do |word|
  if table[word]
    table[word] += 1
    count += table[word]
  else
    table[word] = 0
  end
end
puts count

 

D - Summer Vacation

class MaxHeap
  def initialize
    @heap = [nil]
    @size = 0
  end
  
  def insert(key)
    @heap << key
    @size += 1
    up_heap(@size / 2)
  end
  
  def up_heap(i)
    return if i.zero?
    l, r = i * 2, i * 2 + 1
    largest = (l <= @size and @heap[l] > @heap[i]) ? l : i
    largest = r if r <= @size and @heap[r] > @heap[largest]
    unless largest == i
      @heap[i], @heap[largest] = @heap[largest], @heap[i]
      up_heap(i / 2)
    end
  end
   
  def remove_root
    a = @heap[1]
    b = @heap.pop
    @size -= 1
    return b if @heap.size == 1
    @heap[1] = b
    down_heap(1)
    a
  end
   
  def down_heap(i)
    return if i > @size
    l, r = i * 2, i * 2 + 1
    largest = (l <= @size and @heap[l] > @heap[i]) ? l : i
    largest = r if r <= @size and @heap[r] > @heap[largest]
    unless largest == i
      @heap[i], @heap[largest] = @heap[largest], @heap[i]
      down_heap(largest)
    end
  end
  
  def size
    @heap.size - 1
  end
end


n, m = gets.split.map(&:to_i)
given = Hash.new {|h, v| h[v] = []}
n.times.each do
  a, b = gets.split.map(&:to_i)
  given[a] << b
end

mh = MaxHeap.new
sum = 0

(1..m).each do |left_day|
  given[left_day].each {|reward| mh.insert(reward)}
  sum += mh.remove_root unless mh.size.zero?
end
puts sum

これを参考にして、優先度付きキューを実装して頑張った。優先度付きキューは以前に自分で実装したのだけれど、バグがあったりして直した。きちんと使える実装(参照)が手に入ってうれしいけれど、そもそも Ruby では標準添付ライブラリにこれがないのだよなあ。Python はあるらしいのに…。
 

E - Coins Respawn

全然わからないのでいろいろ参考にする。これが参考になりまくり。パクった。

INF = 1 << 60

n, m ,p = gets.split.map(&:to_i)
g = []
to = Array.new(n + 1) {[]}
ot = Array.new(n + 1) {[]}
m.times do
  a, b, c = gets.split.map(&:to_i)
  g << [a, b, -(c - p)]
  to[a] << b
  ot[b] << a
end

toflag = [0] * (n + 1)
toflag[1] = 1
iki = ->(v) {
  to[v].each do |u|
    if toflag[u].zero?
      toflag[u] = 1
      iki.(u)
    end
  end
}
iki.(1)

otflag = [0] * (n + 1)
otflag[n] = 1
kaeri = ->(v) {
  ot[v].each do |u|
    if otflag[u].zero?
      otflag[u] = 1
      kaeri.(u)
    end
  end
}
kaeri.(n)

cand = toflag.zip(otflag).map {|a, b| a * b}
max_count = cand.count(1)
g.select! {|a, b, _| cand[a] == 1 && cand[b] == 1}

bellman_ford = ->{
  inf = INF
  d = Array.new(n + 1, inf)
  d[1] = 0
  max_count.times do
    update = false
    g.each do |v, u, cost|
      if d[v] != inf && d[u] > (a = d[v] + cost)
        d[u] = a
        update = true
      end
    end
    return -d[n] unless update
  end
  inf
}
ans = bellman_ford.()

ans = (ans == INF) ? -1 : [ans, 0].max
puts ans

なんと、Float::INFINITY1 << 60 に直したら TLE が解消された。ははあ、なるほど。

AtCorder/ABC(その1)

ABC001

A - 積雪深差

puts gets.to_i - gets.to_i

 
B - 視程の通報

ans = case (m = gets.to_i)
      when 0...100      then 0
      when 100..5000    then m / 100
      when 6000..30000  then m / 1000 + 50
      when 35000..70000 then (m / 1000 - 30) / 5 + 80
      else 89
      end
puts sprintf "%02d", ans

 
C - 風力観測

Houi = %W(NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)
Fuuryoku_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]]
 
deg, dis = gets.split.map(&:to_i)
kazamuki = "N"
 
112.5.step(3265.5, 225).with_index do |d, i|
  kazamuki = Houi[i] if d <= deg && deg < d + 225
end
 
fuusoku = (dis / 60.0).round(1)
fuuryoku = 12
Fuuryoku_table.each_with_index do |f, i|
  fuuryoku = i if fuusoku.between?(f.first, f.last)
end
 
kazamuki = "C" if fuuryoku.zero?
puts "#{kazamuki} #{fuuryoku}"

 
D - 感雨時刻の整理

memo = gets.to_i.times.map {gets.split("-").map(&:to_i)}
modified = memo.map do |t0|
  t0.map.with_index do |t, i|
    m = (t / 100) * 60 + t % 100
    m += 4 if i > 0
    m = (m / 5) * 5
    (m / 60) * 100 + m % 60
  end    
end.sort
 
be, af = modified.shift
modified.each do |s, e|
  if s.between?(be, af)
    af = e if e > af
  else
    puts sprintf "%04d-%04d", be, af
    be, af = s, e
  end
end
puts sprintf "%04d-%04d", be, af

5分単位の時刻に丸めるのが上手くいっていなかった。きちんと分に直してやらないといけないのね。
別解。

Day = 60 * 24
work = Array.new(Day + 1, 0)
 
gets.to_i.times.map {gets.split("-").map(&:to_i)}.each do |t0|
  t0.each_with_index do |t, i|
    m = (t / 100) * 60 + t % 100
    m += 4 if i > 0
    m = (m / 5) * 5
    work[m] += i.zero? ? 1 : -1
  end    
end
 
Day.times {|i| work[i + 1] += work[i]}
 
be = nil
(Day + 1).times do |t|
  if !be && work[t] > 0
    be = (t / 60) * 100 + t % 60
  elsif be && work[t] < 1
    af = (t / 60) * 100 + t % 60
    puts sprintf "%04d-%04d", be, af
    be = nil
  end
end

いもす法。
 

ABC002

A - 正直者

a, b = gets.split.map(&:to_i)
puts a > b ? a : b

あるいは

puts gets.split.map(&:to_i).max

 
B - 罠

puts (gets.chomp.chars - %W(a i u e o)).join

 
C - 直訴

xa, ya, xb, yb, xc, yc = gets.split.map(&:to_i)
puts ((xa - xc) * (yb - yc) - (xb - xc) * (ya - yc)).abs / 2.0

 
D - 派閥

n, m = gets.split.map(&:to_i)
relations = Hash.new {|h, k| h[k] = [k]}
 
m.times do
  x, y = gets.split.map(&:to_i)
  relations[x] << y
  relations[y] << x
end
 
n.downto(1) do |i|
  [*1..n].combination(i) do |persons|
    if persons.all? {|p| persons & relations[p] == persons}
      puts i
      exit
    end
  end
end

最大クリーク問題だってさ。最大で12人しかいないので、総当りで解いている。
 

ABC003

A - AtCoder社の給料

n = gets.to_i
puts (1..n).inject(0) {|acc, i| acc + 10000 * i * Rational(1, n)}.to_i

AOJ(問題集)21

0200 Traveling Alone: One-way Ticket of Youth

until (given = gets.split.map(&:to_i)) == [0, 0]
  n, m = given
  edge = Array.new(m) {[]}
  h = Array.new(m) {[]}
  n.times do
    a, b, cost, time = gets.split.map(&:to_i)
    a -= 1
    b -= 1
    edge[a][b] = edge[b][a] = [cost, time]
    h[a] << b
    h[b] << a
  end
  
  gets.to_i.times do
    p, q, r = gets.split.map(&:to_i)
    p -= 1
    q -= 1
  
    shortest = Array.new(m, Float::INFINITY)
    done = m.times.map(&:itself)
    shortest[p] = 0
    
    until done.empty?
      u = done.min {|a, b| shortest[a] <=> shortest[b]}
      done.delete(u)
      
      h[u].each do |v|
        if (a = shortest[u] + edge[u][v][r]) < shortest[v]
          shortest[v] = a
        end
      end
    end
    
    puts shortest[q]
  end
end

ダイクストラ法なのだが、他の人の回答を見て徹底的に高速化する。これで 3.30秒。
 

0201 Wrought Gold Master

until (n = gets.to_i).zero?
  costs = n.times.map { gets.split.tap {|a| a[1] = a[1].to_i} }.to_h
  
  m = gets.to_i
  recipe = Hash.new {|hash, key| hash[key] = []}
  m.times do
    given = gets.split
    recipe[given[0]] += given[2..-1]
  end
  goal = gets.chomp
  
  try = ->(parent) {
    r = recipe[parent]
    c = costs[parent]
    if r.empty?
      c
    else
      made = r.map {|child| try.(child)}.sum
      [made, c].min
    end
  }
  puts try.(goal)
end

DFS(深さ優先探索)。錬金釜で作った方が安いかチェックを入れる。
 

0202 At Boss's Expense

require "prime"

until (given = io.gets.split.map(&:to_i)) == [0, 0]
  dishes = given[0].times.map {io.gets.to_i}
  
  result = 0
  dp = Array.new(given[1] + 1, false)
  dp[0] = true
  
  (1..given[1]).each do |i|
    dishes.each do |price|
      if i >= price && dp[i - price]
        dp[i] = true
        break
      end
    end
    result = i if dp[i] && i.prime?
  end
  
  puts result.zero? ? "NA" : result
end

時間オーバー。これは Ruby ではかなり無理っぽい。出来ている人は一人しかいない。
 

0203 A New Plan of Aizu Ski Resort

loop do
  w, h = gets.split.map(&:to_i)
  break if w + h == 0
  
  field = h.times.map {gets.split.map(&:to_i)}
  dp = Array.new(h) {Array.new(w, 0)}
  w.times {|x| dp[h - 1][x] = 1 if field[h - 1][x] != 1}
  
  (h - 2).downto(0) do |y|
    w.times do |x|
      case field[y][x]
      when 2
        if y + 2 == h
          dp[y][x] = 1
        else
          dp[y][x] = dp[y + 2][x]
        end
      when 0
        s = 0
        [-1, 0, 1].each do |dx|
          x1 = x + dx
          next if x1 < 0 || x1 == w
          next if dx.nonzero? && field[y + 1][x1] == 2
          s += dp[y + 1][x1]
        end
        dp[y][x] = s
      end
    end
  end
  
  puts dp[0].sum
end

動的計画法これをパクリましたよ。いやー、むずかしいなあ。
 

0204 UFO Shooting Down Operation

class Ufo
  def initialize(x, y, r, v)
    @dist = Math.sqrt(x ** 2 + y ** 2)
    @x = x
    @y = y
    @r = r
    @v = v
    @ex = x / @dist
    @ey = y / @dist
    @vx = -v * @ex
    @vy = -v * @ey
  end
  attr_reader :x, :y, :r, :dist, :ex, :ey
  
  def move
    @dist -= @v
    @x += @vx
    @y += @vy
  end
end

loop do
  radius, n = gets.split.map(&:to_i)
  break if (radius + n).zero?
  
  ufos = n.times.map {Ufo.new(*gets.split.map(&:to_i))}
  count = 0
  
  loop do
    ufos.each(&:move)
    ufos.sort_by! {|u| u.dist}
    
    ufos1 = ufos.select {|u| u.dist <= radius}
    count += ufos1.size
    ufos -= ufos1
    break if ufos.size.zero?
    
    min = ufos.shift
      
    ufos = ufos.reject do |u|
      r = (min.y * u.x - min.x * u.y).abs / min.dist
      r < u.r &&
          u.dist * (min.ex * u.ex + min.ey * u.ey) +
             Math.sqrt(u.r ** 2 - r ** 2) > radius
    end
    break if ufos.size.zero?
  end
  
  puts count
end

これむずかしすぎでしょう。検索して初めてわかった。
 

0205 Rock, Paper, Scissors

until (a = gets.to_i).zero?
  given = [a] + 4.times.map {gets.to_i}
  
  hands = given.uniq
  if hands.size == 3 || hands.size == 1
    result = [3] * 5
  else
    point = (hands[0] - hands[1]) % 3 == 2 ? 1 : 2
    result = given.map do |hand|
      hand == hands[0] ? point : 3 - point
    end
  end
  
  puts result
end

突然簡単に。
 

0206 Next Trip

until (l = gets.to_i).zero?
  data = 12.times.map {gets.split.map(&:to_i)}
  month_number = "NA"
  
  acc = 0
  data.each_with_index do |mn, i|
    acc += mn[0] - mn[1]
    if acc >= l
      month_number = i + 1
      break
    end
  end
  
  puts month_number
end

簡単。
 

0207 Block

Position = Struct.new(:x, :y)

loop do
  w, h = gets.split.map(&:to_i)
  break if (w + h).zero?
  field = Array.new(h + 1) {Array.new(w + 1, 0)}
  
  xs, ys = gets.split.map(&:to_i)
  xg, yg = gets.split.map(&:to_i)
  start = Position.new(xs, ys)
  
  gets.to_i.times do
    color, direction, x, y = gets.split.map(&:to_i)
    width, height = direction.zero? ? [4, 2] : [2, 4]
    height.times do |h1|
      width.times {|w1| field[y + h1][x + w1] = color}
    end
  end
  
  start_color = field[ys][xs]
  field[ys][xs] = 100
  stack = [start]
  result = "NG"
  
  while (po = stack.shift)
    if po.x == xg && po.y == yg
      result = "OK"
      break
    else
      [[1, 0], [0, -1], [-1, 0], [0, 1]].each do |dx, dy|
        next_x, next_y = po.x + dx, po.y + dy
        next if next_x <= 0 || next_x > w || next_y <= 0 || next_y > h
        if field[next_y][next_x] == start_color
          stack << Position.new(next_x, next_y)
          field[next_y][next_x] = 100
        end
      end
    end
  end
  
  puts result
end

幅優先探索。簡単。
 

0208 Room Numbers of a Hospital

Table = [0, 1, 2, 3, 3, 4 ,4, 5, 6, 7]

def func(num)
  num1 = num.to_s.chars
  result = 0
  loop do
    top = num1.shift.to_i
    digits = num1.size
    result += Table[top] * 8 ** digits
    break if digits.zero?
  end
  result
end

until (num = gets.to_i).zero?
  puts (1..9358757000).bsearch {|i| num <= func(i)}
end

何かダメ。検索してみる。

Table = [0, 1, 2, 3, 5, 7, 8, 9]

def f(n)
  f(n / 8) if n >= 8
  print Table[n % 8]
end

until (num = gets.to_i).zero?
  f(num)
  puts
end

世の中にはかしこい人がいますな。
 

0209 Scene in a Picture

loop do
  n, m = gets.split.map(&:to_i)
  break if (n + m).zero?
  
  scene   = n.times.map {gets.split.map(&:to_i)}
  picture = m.times.map {gets.split.map(&:to_i)}
  
  pictures = []
  4.times do
    pictures << picture 
    picture = picture.reverse.transpose    #右回転
  end
  
  check = ->{
    result = []
    (0..n - m).each do |y|
      (0..n - m).each do |x|
        pictures.each do |pic|
          catch :jump {
            nx = ny = nil
            m.times do |dy|
              m.times do |dx|
                next if pic[dy][dx] == -1
                nx, ny = x + dx, y + dy unless nx
                throw :jump if pic[dy][dx] != scene[y + dy][x + dx]
              end
            end
            result << [nx + 1, ny + 1]
          }
        end
      end
      return result unless result.empty?
    end
    "NA"
  }
  result = check.()
  
  if result != "NA"
    result = result.sort! {|a, b| (a[1] <=> b[1]).nonzero? || a[0] <=> b[0]}[0].join(" ")
  end
  puts result
end

凡庸なコード。でも Ruby では三人しか出来ていないね。

E: ロック /var/lib/dpkg/lock-frontend が取得できませんでした - open (11: リソースが一時的に利用できません)

追記
ここへいらっしゃった方は、たぶん unattended-upgrades のせいで apt が使えないのだと思います。以下を見ることをお勧めします。
marginalia.hatenablog.com


Ubuntu で apt を使おうとしたら以下が出る。

E: ロック /var/lib/dpkg/lock-frontend が取得できませんでした - open (11: リソースが一時的に利用できません)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?

 

対策

$ sudo rm /var/lib/apt/lists/lock
$ sudo rm /var/lib/dpkg/lock
$ sudo rm /var/lib/dpkg/lock-frontend

 
これでダメなら

$ sudo apt autoremove

これだけでもいけると書いてあるサイトもある。

※参考
Ubuntu 18.04¤Çlock¥Õ¥¡¥¤¥ë´ØÏ¢¤ÎÉÔ¶ñ¹ç | ¤Í¤³¤á¤â
 

追記

上の原因が unattended-upgrades によるものなら、以下を試した方がよい。
Ubuntu で unattended-upgrades を無効にする - Marginalia

Ruby 2.6 と RubyInstaller2

ridk use というコマンドが使える。

C:\Users\知生\Documents\code\Ruby>ridk use
1 - C:/Ruby25   ruby 2.5.5p157 (2019-03-15 revision 67260) [i386-mingw32]
2 - C:/Ruby25-x64       ruby 2.5.5p157 (2019-03-15 revision 67260) [x64-mingw32]

3 - C:/Ruby26   ruby 2.6.3p62 (2019-04-16 revision 67580) [i386-mingw32]
4 - C:/Ruby26-x64       ruby 2.6.3p62 (2019-04-16 revision 67580) [x64-mingw32]
Select ruby version to enable: 3
Disable C:/Ruby25
Disable C:/Ruby25
Disable C:/Ruby26
Disable C:/Ruby26-x64
Enable C:/Ruby26

C:\Users\知生\Documents\code\Ruby>ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [i386-mingw32]

※参考
WindowsにおけるRubyやRailsの環境構築方法をいろいろ調べてみた(2017年3月版) - Qiita