ABC291の振り返り(A, B, C, D, E)
振り返りです。
def test_all(f): for i, data in enumerate(eval(f'test_data{f.__name__[0]}')): exp = data["out"] ans = f(*data["in"]) result = "AC" if exp == ans else "WA" print(f"{i+1} {result}: expected: {exp}, output: {ans}")A - camel Case
提出:#39225518
B - Trimmed Mean
提出:#39231783
C - LRUD Instructions 2
やってみよう!
C
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
振り返り
振り返ってゼロからやってみたのがこちら。
from collections import defaultdict def C(N, S): move = { "R": lambda x, y: (x + 1, y), "L": lambda x, y: (x - 1, y), "U": lambda x, y: (x, y + 1), "D": lambda x, y: (x, y - 1), } now = (0, 0) points = defaultdict(int, {now: 1}) for c in S: nxt = move[c](*now) if points[nxt]: return "Yes" break else: points[nxt] += 1 now = nxt else: return "No" test_all(C)結果:#39371279
自由欄
コンテスト中
コンテスト中の提出がこちら。
とりあえずset
にぶっこんで後から要素数を数えてるんですね。
なんかコンテスト中のほうが時間に追われてるせいか、無駄がない実装ができてるな笑(でも1回WA出したのは内緒)
結果:#39240915
自由欄
D - Flip Cards
やってみよう!
D
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
コンテスト中
単純なDPです。
段々DPが解けるようになってきて嬉しい😊
結果:#39253036
自由欄
E - Find Permutation
やってみよう!
E
関数を完成させて「Run」ボタンをクリックしよう!
自由欄
コンテスト中
コンテスト中は「DFSで葉まで辿り着いた時に全ての数字を通っていれば"Yes"だろう」って考えで実装したのが以下。
ブラウザ環境で実行するために余計な処理が入ってますが、基本は単純なDFSです。
が、TLEとなりその後微修正を繰り返すもACならず試合終了。
from collections import defaultdict, deque def E(N, M, XY): out = StringIO() edge = defaultdict(list) larger = set() for X, Y in XY: larger.add(Y) edge[X].append(Y) route = [] exit = [False] def dfs(n): if exit[0]: return route.append(n) if len(route) == N: _, ans = zip(*sorted(zip(route, range(1, N + 1)))) print("Yes", file=out) print(*ans, file=out) exit[0] = True for nxt in edge[n]: dfs(nxt) route.pop() first = set(range(1, N + 1)) - larger if len(first) > 1: print("No", file=out) else: dfs(first.pop()) if not exit[0]: print("No", file=out) return out.getvalue() test_all(E)結果:#39261710
振り返り
「DFSの計算量って$O(N + M)$なのになんでTLEなんの!?😡」と思ったのですが、今回のように「葉にたどり着いたときに全ての数字を通っている」ことを確認するためには一度通った頂点や辺を何度も重複して探索する必要があるんですね。
通常の全探索を行うDFSなら一度通った頂点はパスするので$O(N + M)$になりますが、上の実装では上記理由からその処理を行っていないのでTLEになるのは当然だったのでした…
ではどうするか。
今回の問題では最短経路ならぬ最長経路を求めているようなものなので、ある頂点に辿り着く経路が複数ある場合、その経路が短い方は明らかに解ではありません。
そのような管理ができるのはBFSで、最短経路を求めるように探索しながら、ある頂点に辿り着いたときにその頂点に辿り着ける別の未探索の経路がある場合にはそれ以上探索しない(最短経路探索なので未探索の経路の方が長い)ことで計算量を$O(N + M)$に抑えることができます。
そんな感じで実装したのが以下。
数字の昇順にインデックスを繋ぐグラフをedge
で、逆方向の降順のグラフをegde
で管理することで上の考えを実現できました。
結果:#39377313
解説で言及されているトポロジカルソートについては、いつか勉強します😇
自由欄