【競プロ】Exam and Wizardを解く
こんにちは、モリリンです。
今日も今日とて、朝から競プロ解いていきます。
今日の問題はキーエンスプログラミングコンテスト2019のC問題、Exam and Wizard です。
問題文
大学生の高橋君は 個の試験を受けてすべてに合格する必要があります. 現在, 番目の試験の準備度は です. また,高橋君の入念な調査によって, 番目の試験に合格するためには準備度を 以上にしなくてはならないことが分かっています.
このままだとすべての試験に合格できないかもしれないと思った高橋君は,魔法使いの青木君に頼んで, 試験の準備度の総和は変えずに,なるべく少ない数の試験の準備度を変更してもらうことで試験を乗り切ることにしました.
高橋君に代わって,以下の条件を満たす数列 を考えたときの と が異なるような の個数の最小値を求めてください. そのような数列 が構成できない場合は−1
を出力してください.
- 数列 の総和と数列 の総和は等しい
- どの に対しても, が成り立つ
制約
ポイント
今回の問題の場合、N
の制約がと少し大きいため、、つまり、ループが一重くらいで計算できたらいいなーくらいの気持で考えます。
考えかた
まずは、入力例1をみていきます。
例1では、 となっています。
準備度 なので、 を 以上に変更する必要があり、最低 を他のところから必要になります。
同じように なので、 を 以上に変更するために最低 必要になります。
なので合計を他の準備度からもらってくる必要があります。
そして、すでに となっているので、 を変更して、余った準備度をそれらの足りていないところに割り当てることができます。
なので、結局全ての準備度を変更する必要があるので、答えは3
となります。
つまり、 となっているについて、の合計分が条件を満たすのに必要で、その分をすでに となっているところから を変更して、余った準備度 を割り当てればいいことになります。
そして、変更回数を最小にするために、 が大きなところから変更して、余った準備度を他に割り当ていきます。
そして求める答えは、
となっているについての、の合計をreq
、
となっている について、を並べたものを extras
、
その合計をs_extra
としたとき、
なら答えは -1
それ以外の時、答えは ( となっているの合計) + (extras
の要素を大きい順から足していって何要素目に req
を超えるか)
になります
実装
上記のことを実装するには、まず、
req
, s_extra
, extras
を宣言します。
なお、 result
は答えを表します。
そして、 について、
- なら、
s_extra
にを足し、extras
にを追加 - なら、
req
にを足し、result
に1を足す
そして、extras
を降順にソートして、
extras
から要素を1つづつ取り出していって、
req
が0以下なら終了- それ以外なら、
req
をその値で引きresult
に1を足す
を繰り返します
Nimで書いたコードは以下になります。
import sequtils, strutils, sugar, algorithm
proc scanf(formatstr: cstring){.header: "<stdio.h>", varargs.}
proc getchar(): char {.header: "<stdio.h>", varargs.}
proc nextInt(): int = scanf("%lld", addr result)
proc nextFloat(): float = scanf("%lf", addr result)
proc nextString(): string =
var get = false
result = ""
while true:
var c = getchar()
if int(c) > int(' '):
get = true
result.add(c)
else:
if get: break
get = false
proc `$` [T](x: seq[T]): string = x.mapIt($it).join(" ")
proc solve(N: int, A: seq[int], B: seq[int]): int =
var req, s_extra = 0
var extras: seq[int]
for i in 0..<N:
if A[i] > B[i]:
s_extra += A[i] - B[i]
extras.add(A[i] - B[i])
elif A[i] < B[i]:
req += B[i] - A[i]
inc(result)
if req > s_extra:
return -1
extras.sort(Descending)
for extra in extras:
if req <= 0:
return result
req -= extra
inc(result)
proc main(): void =
var N = 0
N = nextInt()
var A = newSeqWith(N, 0)
for i in 0..<N:
A[i] = nextInt()
var B = newSeqWith(N, 0)
for i in 0..<N:
B[i] = nextInt()
echo solve(N, A, B)
return
main()
終わりに
いかがだったでしょうか?
今回のような問題は、実際に入力例などを手で描いてみて、自分ならどうやって解くのかを考え、それをコードに落としていく、みたいなことをやるとうまくいくと思います。