コドフォEducational 90 A~D解説[python]
結果:A~Dの4完遅解きでぎり青パフォくらい
A - Donut Shops
算数、パズル
概要
2つの店A,Bがある。
Aではドーナツを1つa ドルでうり、Bではb 個単位でc ドルでうる。
考察
式に落とすとb*k < c*ceil(k/b) だが、この中で、1つでも条件を満たすものを考えれば良い(コドフォでよくある)
この中で、1つでも条件を満たすものを考えれば良い(コドフォでよくある)は、閾値を考える
B が安くなるのは、ちょうど単位セットで変えた時で最小はb の時
Aが安くなるのはB が最も余分が多い時で1こしか買わないとき
実装
import sys import math read = sys.stdin.buffer.read input = sys.stdin.buffer.readline readlines = sys.stdin.buffer.readlines t = int(input()) for case in range(t): a, b, c = map(int, input().split()) if a >= c: print(-1, end=" ") else: print(1, end=" ") if a * b <= c: print(-1) else: print(b)
全体で10min
if a*b <= c : else の箇所で出力を1 にしてて1WA出した。(ちゃんと解けたと思っても確認しようね)
B - 01 Game
ゲーム
考察:
動けなくなる時とは?:隣接した文字が全て同じ文字なら(1種類の文字だけになれば動けない)
必ず1回の操作で0,1が1つずつ減る
場所や順番は関係ないので 1,0の少ない方の個数が奇数なら先行が勝つ
文字列で/b を除きたい時ってどうやるんだっけ?
実装
import sys import math read = sys.stdin.buffer.read # input = sys.stdin.buffer.readline readlines = sys.stdin.buffer.readlines t = int(input()) for case in range(t): s = input() zero_num = s.count("0") # 小さい方が奇数なら勝ち ただし0の場合は数えない if min(len(s) - zero_num, zero_num) == 0: print("NET") elif min(len(s) - zero_num, zero_num) % 2: print("DA") else: print("NET")
C - Pluses and Minuses
コードの理解、累積和(事前計算)、定式化
二重ループ
考察
内側をみるとbreakされないならlen(s) -1 になる
先頭から見てcur より- の数が+より大きくなったら終了
外側はok だったらberakする
最後まで行ってもcur がずっと0以上なら続ける
定式化すると、累積わ*-1を持っておいて、1,2,3...と回してそこまでの分を足せば良い
O(N)
実装
import sys import math read = sys.stdin.buffer.read # input = sys.stdin.buffer.readline readlines = sys.stdin.buffer.readlines t = int(input()) for case in range(t): s = input() n = len(s) ans = 0 cnt = [0] * (1 + n) cum = 0 for i in range(n): if s[i] == "-": cum += 1 else: cum -= 1 if cum > 0 and cnt[cum] == 0: ans += i + 1 cnt[cum] = i + 1 # 最後まで行ったケースを考える。 ans += i + 1 print(ans)
D - Maximum Sum on Even Positions
数列の操作、反転、累積和、実装ゲー
考察
偶数番目にくる数がどのように変わるだけを見れば良い。
l,r の偶奇で場合わけする
even,even => 変わらない
even , odd => 範囲内の選択が逆転
odd, even => 同様
odd,odd => 変わらない
任意の地点に対して、そこまでの偶数、奇数それぞれの累積和を持って差分の差分を計算してmax を取れば良さそう
どうやってmaxを計算するか?
まとめたい。偶数の時は+ 奇数は- の累積和をとる
累積わの区間の最大はどうやって求める?
現在のmax, minを持ってそれぞれ更新する感じ
実装
step1 : 現在の偶数番目の和を計算
step2: 累積和を計算する
step3: 偶数番目、奇数番目それぞれ累積和の列に対して、現在の最大、最小をそれぞれ更新して差分のmaxを計算
import sys import math read = sys.stdin.buffer.read # input = sys.stdin.buffer.readline readlines = sys.stdin.buffer.readlines t = int(input()) for case in range(t): n = int(input()) a = list(map(int, input().split())) """step1 : 現在の偶数番目の和を計算 step2: 累積和を計算する step3: 偶数番目、奇数番目それぞれ累積和の列に対して、現在の最大、最小をそれぞれ更新して差分のmaxを計算 """ origin = sum([a[i] for i in range(n) if i % 2 == 0]) acc = [0] * (1 + n) for i in range(n): if i % 2: acc[i + 1] = acc[i] + a[i] else: acc[i + 1] = acc[i] - a[i] # 偶数に対して現在のmax,minを更新=> min のみの管理 ans_dif = 0 # print(origin, acc) even_min = acc[0] for i in range(n // 2 + 1): even_min = min(even_min, acc[i * 2]) ans_dif = max(ans_dif, acc[i * 2] - even_min) odd_min = acc[1] for i in range((1 + n) // 2): odd_min = min(odd_min, acc[i * 2 + 1]) ans_dif = max(ans_dif, acc[i * 2 + 1] - odd_min) print(ans_dif + origin)
こういう問題は遷移を頭の中でイメージできなくて難しい。典型的な問題みたいなので慣れかな。