ABC153:水色競プロerのムーブ備忘録(バグったら書き直しましょう。一から……いいえ、ゼロから!)
〇コンテスト名:ABC153
〇配点 A:100 B:200 C:300 D:400 E:500 F:600
〇制限時間 100分
いつも通りのABC
〇コンテスト開始時のsyunsukeのレート 1367
〇今回の方針
いつも通り。
基本前から順番に解く。
Cまではテストケースも程々に速度重視で。
(Dが難しく、Cまでのペナで死にたくないので。)
はまったら順位表をチェック。
・今見てる問題を飛ばす?
・何か簡単な解法がある?
の判断材料に
コンテスト開始!
A:Hの体力をもつモンスターに一回でAの体力を削る。何回で体力を0以下にできるか?
pythonなら、mathのceilを使えば良いですね。
import math H,A=map(int,input().split()) print(math.ceil(H/A))
1:43 AC
B:Hの体力をもつモンスターに一回でAiの体力を削る必殺技を食らわせる。必殺技は一種につき一回。N種の必殺技でモンスターの体力を0以下にできるか?
Aをリストで受けて、リストの合計(sum(A))とHの大きさを比較すれば良いですね。
H,N=map(int,input().split()) A=list(map(int,input().split())) if H-(sum(A))<=0: print("Yes") else: print("No")
3:57 AC
C:N体のモンスターがいる。体力はそれぞれHiで与えられる。1劇でモンスターを仕留められる必殺技をK回放てる。それ以外は1ずつ体力を削る。最低何回でモンスターを全滅させられるか?
自然に考えて、体力の大きいモンスターから順に必殺技を放ち、残りは1ずつ削る。
ではどうやって体力の大きいモンスターを探すか?
Hをリストで受けて、降順で並べ替える。
H.sort(reverse=True)を使えば、大きい方から順に並びます。
並べたら、最初からK体のモンスターの体力を0にして、あとはモンスターの体力の合計(sum(H))を出力すればOK
!!制約にKはNより小さいとは書いていません。
KがNより大きい場合、K体のモンスターの体力を0にしようとしたらバグりそうですね。
危ない
N,K=map(int,input().split()) H=list(map(int,input().split())) H.sort(reverse=True) for i in range(min(K,N)): H[i]=0 print(sum(H))
6:32 AC
D:体力Hのモンスターがいる。H=1のときに攻撃すればモンスターは死ぬ。H>1なら体力H//2のモンスター2体に分裂する。何回の攻撃で倒せる(全滅させられる)か?
攻撃して、倒せなければ、モンスターの数は倍になって、それぞれのモンスターの体力は半分(小数点以下切り捨て)になる。
難しいことは考えずに、そのままコードに落としましょう。
答えはans
モンスターの数をNumとしてます。
H=int(input()) ans=0 Num=1 for i in range(100): if H==0: break else: ans+=Num H//=2 Num*=2 print(ans)
ループの回数を100回にしていますが、
1回モンスターに攻撃するとモンスターの体力は2**1分の1に
10回攻撃すると2**10分の1に
ここで2**10>10**3は覚えておくと便利です。
制約からHは10**12以下
10回の攻撃で10**3分の1以下まで体力を削れるので
40回攻撃すれば、10**12分の1以下に削れます。
それを考えれば50回のループでも良いですね。
H=0となった時点で6行目のbreakでループを止めて
答えを出力
11:35 AC
E:Hの体力を持つモンスターにN種類の魔法を食らわせる。各魔法はAiのダメージを与え、魔力をBi消費する。モンスターの体力を0にするために必要な最小の魔力の消費はいくらか?
どう見てもDPですね。
しかも、テストケースを見ると、魔力の消費の上限はかなり高い。でも制約を読むと体力の上限は10**4。
ここまでわかればあとはコードに落とすだけ。さっさと解きましょう。
・・
・・
・・
あれ?テストケース3が通りません。
途中で割り算を使ったから誤差が出ているのでしょうか?
割り算してmath.ceilで切り上げて・・
いや。それなら誤差はないでしょう。
一旦離脱してFを見てみましょう。
区間更新のライブラリがあれば解けそうですね。持ってませんけど。
こんな時は究極奥義。
全部消して
「ここからはじめましょう、一から……いいえ、ゼロから!」
あっさりテストケース通ります。
アルゴリズムが間違っていない自信があるのにテストケースに通らない場合は早めにやり直すべきですね。
今回はその判断が遅すぎました。
H,N=map(int,input().split()) L=[] for i in range(N): a,b=map(int,input().split()) L.append([a,b]) L.sort() import math X=math.ceil(H/L[i][0]*L[i][1]) dp=[10**20 for i in range(10**4+100)] dp[0]=0 for i in range(N): for j in range(len(dp)): if j%L[i][0]==0: Y=j//L[i][0] else: Y=j//L[i][0]+1 if j-L[i][0]>=0: dp[j]=min(dp[j],Y*L[i][1],dp[j-L[i][0]]+L[i][1]) else: dp[j]=min(dp[j],Y*L[i][1]) print(dp[H])
汚いコードですが通りました。
10分で書けるコードを40分もバグがとれずに悩んでいてはコンテストで勝てません。
おまけにdpのリストの数を10**4にしてしまうミス(0から10**4まで欲しいので、10**4+1個もしくはN+1個のリストにしなければなりません)で1ペナ
60::09 AC 1ペナ
F:N体のモンスターがいる。各モンスターの位置はXi体力はHi。攻撃は指定座標±Dに届く。何回で全滅させられるか?
区間の値を更新するライブラリが欲しいですね。
Google先生に期待しましょう。
それっぽいライブラリはすぐ見つかりますが、使い方がわかりません。
残り10分を切った頃
あれ?左端から攻撃して、攻撃の届く右の端と、その時与えるダメージの値をリストにしておいて、しゃくとり法を使えばライブラリいらない?
遅すぎました。
10分未満ではコードにできません。
Eで時間をロスしすぎなければあるいは・・
結局60:09で1ペナ5完
1587位でパフォ1137 レートは-21で1346になりました。
アルゴリズムに自信があるのにバグが取れないなら潔く書き直す。
次回以降の反省です!