AtCoder ABC128C (関数型Ruby?)

https://atcoder.jp/contests/abc128/tasks/abc128_c

きれいに Ruby らしく解けたので、メモ。

n, m = gets.split.map(&:to_i)
cond = m.times.map {
  k, *ss = gets.split.map(&:to_i)
  ss.inject(0) {|acc, s| acc | 1 << (s - 1)}
}.zip(gets.split.map(&:to_i))

puts (2 ** n).times.count {|switches|
  cond.all? {|c, p| (switches & c).to_s(2).count("1") % 2 == p}
}

11ms。関数型 Ruby(笑)

  • cond[i]は、i + 1 番目の電球の条件[c, p]で、cはkビット目がスイッチkの状態(1ならばon)という条件を表す。電球の個数はm
  • acc |= 1 << s は、acc のsビット目(最初が0ビット目)を立てる。
  • cond.all? {|c, p| (switches & c).to_s(2).count("1") % 2 == p} は、スイッチの状態がswitchesのとき、すべての電球が on ならば true になる。
  • switchesはスイッチの状態で、kビット目がスイッチkの on/off を表す。スイッチはn個あるので、総当りの状態数は 2^n 個ある。nが最大でも10なので、2^10 = 1024。これだけの回数をcount で回して true の個数を数える。

for, times, each, uptoなどのループをまったく使わず、map, inject, zip, all? などで頑張っております(times.map は許せ笑)。