Codeforces Round #799 (Div. 4) in Ruby
概要
ロシアの競技プログラミングサイト Codeforces のコンテスト「Codeforces Round #799 (Div. 4)」を Ruby で解いたので解説します。
A - Marathon
問題文(意訳)
ティムールと他
ただし、
解説
コード
t = gets.to_i
t.times do
# b, c, d をまとめて xs とした
a, *xs = gets.split.map(&:to_i)
puts xs.count { _1 > a }
end
B - All Distinct
問題文(意訳)
ショウは
ヒント
解説
まず、それぞれの値について、要素がいくつあるか集計します。このとき、値
削除するべき要素が偶数個なら、削除するべき要素同士でペアにできるので、
しかし、削除するべき要素が奇数個のときは、ペアを作るために、消すべき要素以外から一つ追加で消す必要があるため、ここに注意が必要です。
コード
t = gets.to_i
t.times do
n = gets.to_i
a = gets.split.map(&:to_i)
# 削除するべき要素の個数
double = a.tally.each_value.sum { |count| count - 1 }
puts n - (double + 1) / 2 * 2
end
C - Where's the Bishop?
問題文(意訳)
ヒント
ビショップが端に置かれることがない場合、あなたにとってどういう良いことがあるでしょうか?
解説
端に置かれないことから、必ず以下の模様が含まれることがわかります。この模様が含まれる位置を探すと良いです。
#.#
.#.
#.#
さらに言うと、この模様が含まれるときのみ、 #
が
コード
t = gets.to_i
t.times do
gets
grid = Array.new(8) { gets.chomp }
(1 .. 6).any? do |i|
(1 .. 6).any? do |j|
# (i, j) が中心にくる 3x3 の正方形の中に、「#」がいくつあるか数える( 5 個ならそこが答え)
if (i - 1 .. i + 1).sum { |i2| (j - 1 .. j + 1).count { |j2| grid[i2][j2] == ?# } } == 5
puts "#{i + 1} #{j + 1}"
true
else
false
end
end
end
end
D - The Clock
問題文(意訳)
ある時刻
解説
愚直にシミュレーションをし、同じ時刻が
コード
require "set"
t = gets.to_i
t.times do
time, _x = gets.split
h = time[0, 2].to_i
m = time[3, 2].to_i
x = _x.to_i
i = h * 60 + m
visited = [false] * (24 * 60)
ans = 0
until visited[i]
visited[i] = true
h, m = i.divmod(60)
h1, h2 = h.divmod(10)
m1, m2 = m.divmod(10)
ans += 1 if h1 == m2 and h2 == m1
i = (i + x) % (24 * 60)
end
puts ans
end
E - Binary Deque
問題文(意訳)
スラヴィックは
解説
配列の累積和をとっておくことで、先頭からいくつ消し、末尾からいくつ消すかを決めたときの総和を
先頭からいくつ消すかを決め打ちし、末尾からいくつ消すかを二分探索すると解けます。
コード
t = gets.to_i
t.times do
n, s = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
if a.sum < s
puts -1
next
end
prefix_sum = [0]
a.each do |x|
prefix_sum << prefix_sum[-1] + x
end
ans = n
(0 .. n).each do |head|
tail = (0 .. n).bsearch { |tail| n - (prefix_sum[head] + prefix_sum[n] - prefix_sum[N - tail]) <= s }
ans = head + tail if ans > head + tail
end
puts ans
end
F - 3SUM
問題文(意訳)
正の整数からなる長さ
ヒント
解説
まず、
これらの組み合わせのうち、入力から作れるものがあるかどうか判定することで、答えることが可能です。
コード
# 和が 3 になる 0 <= x <= y <= z <= 9 の組み合わせを列挙
combinations = []
[* 0 .. 9].repeated_combination(3) do |a|
if a.sum % 10 == 3
counts = [0] * 10
a.each do |x|
counts[x] += 1
end
combinations << counts
end
end
t = gets.to_i
t.times do
n = gets.to_i
a = gets.split.map(&:to_i)
counts = [0] * 10
a.each do |x|
counts[x % 10] += 1
end
# 3 になる組み合わせのうち、入力から作れるものがあるか
ans = combinations.any? { |counts2| (0 .. 9).all? { |x| counts[x] >= counts2[x] } }
puts ans ? "YES" : "NO"
end
G - 2^Sort
問題文(意訳)
ヒント
条件は、隣り合う要素に関する条件に言い換えることができます。
解説
どの隣り合う要素についても、前の要素が次の要素の
ここで、隣り合う要素のペアそれぞれについて、条件を満たすなら
長さ
コード
t = gets.to_i
t.times do
n, k = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
b = a.each_cons.map { |x, y| (x < y * 2) ? 1 : 0 }
prefix_sum = [0]
b.each do |x|
prefix_sum << prefix_sum[-1] + x
end
puts (0 ... n - k).count { |i| prefix_sum[i + k] - prefix_sum[i] == k }
end
H - Gambling
問題文(意訳)
マリアンはカジノにいます。このカジノでできるゲームはいくつかの次のような形式です。
- 毎ラウンド、プレイヤーは数を言う。次に、
から1 までの目があるサイコロが振られる。出た目と言った数が一致していれば掛け金が倍になるが、外れれば、掛け金は半分になる。(小数点以下は丸められない。例えば、10^9 を半分にすると1 になる。)\frac{1}{2}
マリアンは予知能力者なので、カジノで出る目が完全にわかっています。
ここで、マリアンは言う数 をひとつに固定し、a ラウンド目からl ラウンド目までに出ることで、掛け金を最大化しようと考えました。掛け金が最大になるときのr の組をひとつ答えてください。a, l, r
解説
まず、それぞれの出目について、それが出るラウンドを記録します。
出目
これは Kadane's Algorithm を使うと、
Kadane's Algorithm は、配列から和が最大になる区間を求めるアルゴリズムです。
コードで表すと、以下のようになります。
# [和の最大値, そのときの左端, そのときの右端] を返す(閉区間)
def kadane(array)
left = 0
sum = 0
ans = [array[0], 0, 0]
array.each_with_index do |x, right|
if sum < 0
left = right
sum = x
else
sum += x
end
if ans[0] < sum
ans = [sum, left, right]
end
end
ans
end
コード
t = gets.to_i
t.times do
n = gets.to_i
x = gets.split.map(&:to_i)
indices = {}
x.each_with_index do |a, i|
(indices[a] ||= []) << i
end
ans = 1
ans_value = [x[0], 1, 1]
indices.each do |a, row|
b = [1]
row.each_cons(2) do |i, j|
b << (i - j + 1) << 1
end
l = 0
sum = 0
b.each_with_index do |x, r|
if sum < 0
l = r
sum = x
else
sum += x
end
if sum > ans
ans = sum
ans_value = [a, row[l / 2] + 1, row[r / 2] + 1]
end
end
end
puts ans_value.join(" ")
end
Discussion