振り返りです。

AtCoder Beginner Contest 278 - AtCoder
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
from copy import deepcopy def test_all(f): for i, data in enumerate(eval(f'test_data{f.__name__[0]}')): exp = data["out"] ans = f(*deepcopy(data["in"])) result = "AC" if exp == ans else "WA" print(f"{i+1} {result}: expected: {exp}, output: {ans}")

A - Shift

B - Misjudge the Time

やってみよう!

B関数を完成させて「Run」ボタンをクリックしよう!

def B(H, M): pass B(1, 23) # 1 23 B(19, 57) # 20 0 B(20, 40) # 21 0

自由欄

try(コンテスト中)

振り返ってみると、めちゃくちゃ無駄なことしてて恥ずかしい…

from datetime import datetime, timedelta def B(H, M): dt = datetime(2000, 1, 1, hour=H, minute=M) def valid_h(h): h10, h1 = divmod(h, 10) return h10 <2 or h10 == 2 and h1 <=3 def valid_m(m): m10, m1 = divmod(m, 10) return m10 <=5 while True: h10, h1 = divmod(dt.hour, 10) m10, m1 = divmod(dt.minute, 10) if valid_h(h10 * 10 + m10) and valid_m(h1 * 10 + m1): break dt += timedelta(minutes=1) print(dt.hour, dt.minute) B(1, 23) # 1 23 B(19, 57) # 20 0 B(20, 40) # 21 0

結果:#36617094

自由欄

try(振り返り)

まず有効な時間の判定がめっちゃ無駄。
そして時間を進めるのも、わざわざdatetime型使わなくても簡単にできるやん…

def B(H, M): def plus1m(h, m): d, m = divmod(m + 1, 60) _, h = divmod(h + d, 24) return h, m def is_valid(h, m): return 0 <= h < 24 and 0 <= m <= 59 while True: h10, h1 = divmod(H, 10) m10, m1 = divmod(M, 10) if is_valid(h10 * 10 + m10, h1 * 10 + m1): break H, M = plus1m(H, M) print(H, M) B(1, 23) # 1 23 B(19, 57) # 20 0 B(20, 40) # 21 0

結果:#36772572

自由欄

C - FF

やってみよう!

C関数を完成させて「Run」ボタンをクリックしよう!

test_dataC = [ { "in":[3, 9, [[1, 1, 2], [3, 1, 2], [1, 2, 1], [3, 1, 2], [1, 2, 3], [1, 3, 2], [3, 1, 3], [2, 1, 2], [3, 1, 2]]], "out": """No Yes No No """ },{ "in":[2, 8, [[1, 1, 2], [1, 2, 1], [3, 1, 2], [1, 1, 2], [1, 1, 2], [1, 1, 2], [2, 1, 2], [3, 1, 2]]], "out": """Yes No """ },{ "in":[10, 30, [[3, 1, 6], [3, 5, 4], [1, 6, 1], [3, 1, 7], [3, 8, 4], [1, 1, 6], [2, 4, 3], [1, 6, 5], [1, 5, 6], [1, 1, 8], [1, 8, 1], [2, 3, 10], [1, 7, 6], [3, 5, 6], [1, 6, 7], [3, 6, 7], [1, 9, 5], [3, 8, 6], [3, 3, 8], [2, 6, 9], [1, 7, 1], [3, 10, 8], [2, 9, 2], [1, 10, 9], [2, 6, 10], [2, 6, 8], [3, 1, 6], [3, 1, 8], [2, 8, 5], [1, 9, 10]]], "out": """No No No No Yes Yes No No No Yes Yes """ },{ "in":[10**9, 8, [[1, 1, 2], [1, 2, 1], [3, 1, 2], [1, 1, 2], [1, 1, 2], [1, 1, 2], [2, 1, 2], [3, 1, 2]]], "out": """Yes No """ } ] def C(N, Q, TAB): pass test_all(C)

自由欄

try(コンテスト中)

人数分の配列を作ろうとして一度TLE…
の後の友達情報をdictで持つバージョンです。存在確認がいかにもめんどくさい。

from io import StringIO def C(N, Q, TAB): out = StringIO() usr = {} for t, a, b in TAB: if t == 1: if a in usr: usr[a].add(b) else: usr[a] = set([b]) elif t == 2: if a in usr: try: usr[a].remove(b) except: pass else: print("Yes" if a in usr and b in usr and b in usr[a] and a in usr[b] else "No", file=out) return out.getvalue() test_all(C)

結果:#36628052

自由欄

try(振り返り)

という訳で、前回の振り返りで存在を知ったdefaultdictをさっそく使ってみます!

from collections import defaultdict def C(N, Q, TAB): out = StringIO() friends = defaultdict(set) for t, a, b in TAB: if t == 1: friends[a].add(b) elif t == 2: try: friends[a].remove(b) except: pass else: print("Yes" if b in friends[a] and a in friends[b] else "No", file=out) return out.getvalue() test_all(C)

結果:#36912354

ほどよくスッキリ書けました😄

解説を見る

解説をトレースするとこんな感じ。
あ、楽…

単純に2者間の関係だけに焦点を当てるなら全然分かりやすいですね。

def C(N, Q, TAB): out = StringIO() friends = set() for t, a, b in TAB: if t == 1: friends.add((a, b)) elif t == 2: try: friends.remove((a, b)) except: pass else: print("Yes" if (a, b) in friends and (b, a) in friends else "No", file=out) return out.getvalue() test_all(C)

結果:#36927846

D - All Assign Point Add

やってみよう!

D関数を完成させて「Run」ボタンをクリックしよう!

# 加工済み test_dataD = [ { "in":[5, {1: 3, 2: 1, 3: 4, 4: 1, 5: 5}, 6, [[3, 2], [2, 3, 4], [3, 3], [1, 1], [2, 3, 4], [3, 3]]], "out": """1 8 5 """ },{ "in":[1, {1: 1000000000}, 8, [[2, 1, 1000000000], [2, 1, 1000000000], [2, 1, 1000000000], [2, 1, 1000000000], [2, 1, 1000000000], [2, 1, 1000000000], [2, 1, 1000000000], [3, 1]]], "out": """8000000000 """ },{ "in":[10, {1: 1, 2: 8, 3: 4, 4: 15, 5: 7, 6: 5, 7: 7, 8: 5, 9: 8, 10: 0}, 20, [[2, 7, 0], [3, 7], [3, 8], [1, 7], [3, 3], [2, 4, 4], [2, 4, 9], [2, 10, 5], [1, 10], [2, 4, 2], [1, 10], [2, 3, 1], [2, 8, 11], [2, 3, 14], [2, 1, 9], [3, 8], [3, 8], [3, 1], [2, 6, 5], [3, 7]]], "out": """7 5 7 21 21 19 10 """ }, ] def D(N, A, Q, query): pass test_all(D)

自由欄

try(コンテスト中)

上のテストデータの時点で加工しているので察しはつくと思いますが、Aをdictで管理します。

def D(N, A, Q, query): out = StringIO() for i, *q in query: # print(A) if i == 1: allA = q[0] A = {} elif i == 2: if q[0] in A: A[q[0]] += q[1] else: A[q[0]] = allA + q[1] else: print(A[q[0]] if q[0] in A else allA, file=out) return out.getvalue() test_all(D)

結果:#36636058

try(振り返り)

またしてもdefaultdictで楽できそう案件です。

以下の7行目で、値を変数に代入するのは必要です。
直接defaultdict(lambda: q[0])とすると、ループでqが更新されたものを拾ってしまいます。

from collections import defaultdict def D(N, A, Q, query): out = StringIO() for i, *q in query: if i == 1: ini = q[0] A = defaultdict(lambda: ini) elif i == 2: A[q[0]] += q[1] else: print(A[q[0]], file=out) return out.getvalue() test_all(D)

結果:#36938500

自由欄

E - Grid Filling

やってみよう!

E関数を完成させて「Run」ボタンをクリックしよう!

# 加工済み test_dataE = [ { "in":[3, 4, 5, 2, 2, [[2, 2, 1, 1], [3, 2, 5, 3], [3, 4, 4, 3]]], "out": """4 4 3 5 3 4 """ },{ "in":[5, 6, 9, 3, 4, [[7, 1, 5, 3, 9, 5], [4, 5, 4, 5, 1, 2], [6, 1, 6, 2, 9, 7], [4, 7, 1, 5, 8, 8], [3, 4, 3, 3, 5, 3]]], "out": """8 8 7 8 9 7 8 9 8 """ },{ "in":[9, 12, 30, 4, 7, [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 20, 20, 2, 2, 5, 9, 10, 9, 9, 23], [2, 29, 29, 29, 29, 29, 28, 28, 26, 26, 26, 15], [2, 29, 29, 29, 29, 29, 25, 25, 26, 26, 26, 15], [2, 29, 29, 29, 29, 29, 25, 25, 8, 25, 15, 15], [2, 18, 18, 18, 18, 1, 27, 27, 25, 25, 16, 16], [2, 19, 22, 1, 1, 1, 7, 3, 7, 7, 7, 7], [2, 19, 22, 22, 6, 6, 21, 21, 21, 7, 7, 7], [2, 19, 22, 22, 22, 22, 21, 21, 21, 24, 24, 24]]], "out": """21 20 19 20 18 17 20 19 18 19 17 15 21 19 20 19 18 16 21 19 19 18 19 18 20 18 18 18 19 18 18 16 17 18 19 17 """ }, ] def E(H, W, N, h, w, A): pass test_all(E)

自由欄

try(振り返り)

コンテスト中の愚直解でTLEとなって何も思いつかないので解説を見ます。

解説多いな~

以下、一番分かりやすかった原案者の想定解法に倣ってやってみました。
整数Aの方に着目して前処理するんですね。なるほど~

from collections import defaultdict def E(H, W, N, h, w, A): out = StringIO() loc = defaultdict(lambda: dict(minx=W, maxx=0, miny=H, maxy=0)) for i, row in enumerate(A): for j, a in enumerate(row): loc[a]["minx"] = min(loc[a]["minx"], j) loc[a]["maxx"] = max(loc[a]["maxx"], j) loc[a]["miny"] = min(loc[a]["miny"], i) loc[a]["maxy"] = max(loc[a]["maxy"], i) for i in range(H - h + 1): ans = [] for j in range(W - w + 1): ans.append(0) for v in loc.values(): if ( v["minx"] >= j and v["maxx"] <= j + w - 1 and v["miny"] >= i and v["maxy"] <= i + h - 1 ): pass else: ans[-1] += 1 print(*ans, file=out) return out.getvalue() test_all(E)

結果:#36942145

自由欄

まとめ

defaultdictが大活躍した回でした。
今後も重用しそう。

自由欄