(要約)
$k$巻まで読むと仮定し、$k$巻以下で重複する本は売却します。
売らずに読む本をs
冊とすると残りはn-s
冊で、それらを全部売って$k$巻まで揃うかどうかをみればよいです。
(注意)
Julia 1.4です。知らなくても理解できるとは思います。
考察
-
2冊の本を売って1冊の本を買うと、本の総冊数は減少する。なのでなるべく売買しないほうがよい
(まず全部売ってしまってから考えるというアプローチは不可) -
$a_i$ の上限が大きい($10^9$)ので対策が必要だが、本の総冊数は最大で$3×10^5$なので解はこの値を超えることはない。
(上界を見積もる) -
売るなら読まれる可能性が最も小さい巻、つまり最後の巻が優先
(貪欲法) -
巻が重複している可能性がある
(コーナーケースというほどではないが。サンプルコードみて初めて気づいた)
アプローチ
k = 0
while true
k += 1
if (k巻まで読める)
continue
else
print(k-1)
exit
endif
end
print(k)
で、$k$巻まで読めるかどうか。
$k$巻まで読めるかどうかの判定は、
- 最初に持っている本のうち、1巻から$k$巻までは2冊以上持っていれば1冊を残して売る … $O(k)$、全探索なら改良できる
- $k+1$巻よりあとは全部売る … $O(N)$、累積和つかえば改良できる
- 売った本で不足している本が買えればOK … 不足している冊数と売れる冊数が分かれば、$O(1)$。
これを$k = 1$から$N$までについて検討すればOK。
ただし愚直に検討すると1回の検討に$O(N)$かかるので全部で$O(N^2)$でTLE
。
計算時間短縮
kについて二分探索
公式解説の2番目の要領です。
コードはシンプルですが、結構高度なことをやっています。
C++の人が実装するなら、「$k$巻より前で重複のため売れる冊数」と「$k+1$巻以上の冊数」を累積和で管理することになるでしょうか。
$O(NlogN)$。
kについて工夫しながら全探索
愚直にやると上記のように$O(N^2)$ですが、$k$を1つずつ増やすので工夫の余地はありそうです。
色々なアプローチがありますが、以下の方法が圧倒的にシンプルなので採用しました↓
$k$巻以下で売らずに読む本をs
冊とします。s
の更新は$O(1)$でできます。
残りはn-s
冊で、それらを全部売って$k$巻まで揃えばよいです。
ACコード
本番の際のACコードです。(コメントはあとで付加)
function solver()
n = toI()
a = toVI()
v = zeros(Int,300000) # v[i]は第i巻を何冊持っているかを表す
for ai in a # ai > 300000 は使用しないので無視してよい
ai > 300000 && continue
v[ai] += 1
end
s = 0 # 売らずに読むことのできることのできる冊数
for i in 1:300000 # 第i-1巻まで読むことが可能なとき、第i巻を読むことができるか
if v[i] ≥ 1 # 1冊以上あれば売らずに読むことができる
s += 1
end
r = n - s # i巻までのみ読むと仮定すると、s冊以外は全部売ることができる
if s + r÷2 < i # r冊売ってr÷2冊買って合計冊数がi冊に満たなければi巻までは読めないので打ち切り
println(i-1)
return
end
end
println(300000) # 打ち切られずにここまでくれば上界
end
toI(x=readline()) = parse(Int,x)
toVI() = [toI(x) for x ∈ split(readline())]
solver()
Datastructures.jl
のcounter
でもっと短いコードにできます。
内部でunordered_map
に相当するものを使用しているので速度は劣ります。
using DataStructures
function solver()
n = toI()
v = toVI() |> counter
s = 0
i = 0
while true
i += 1
if v[i] ≥ 1
s += 1
end
r = n - s
if s + r÷2 < i
println(i-1)
return
end
end
end
toI(x=readline()) = parse(Int,x)
toVI() = [toI(x) for x ∈ split(readline())]
solver()
JuliaはJITなのでコンパイル時間の分だけ不利ですが、1.4から1.8ではかなり改善しています。次の言語アップデートが待ち遠しいです。