入緑しました!
という訳で振り返りです。

なお、今回からテスト関数を修正して本番同様input()等で入力を取得するようにしています。

AtCoder Beginner Contest 293 - AtCoder
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
import sys from io import StringIO input = lambda: sys.stdin.readline()[:-1] def test(f, data): stdin = sys.stdin stdout = sys.stdout sys.stdin = StringIO(data["in"]) out = StringIO() sys.stdout = out err = None try: f() except BaseException as e: err = e else: ans = out.getvalue() exp = data["out"] sys.stdin = stdin sys.stdout = stdout if err: raise err result = "AC" if exp == ans else "WA" print(f"{result}: expected: {exp}, output: {ans}") def test_all(f): for i, data in enumerate(eval(f'test_data{f.__name__[0]}'), 1): print(f"case {i}") test(f, data)

A - Swap Odd and Even

やってみよう!

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

test_dataA = [ { "in":"abcdef\n", "out": "badcfe\n" },{ "in":"aaaa\n", "out": "aaaa\n" },{ "in":"atcoderbeginnercontest\n", "out": "taocedbrgeniencrnoetts\n" }, ] def A(): pass test_all(A)

自由欄

振り返り

コンテスト中は思考停止で設問のまま実装しました。
振り返ると、こんなやり方もあったなぁというのが以下。

def A(): S = input() print(*["".join(x) for x in zip(S[1::2], S[0::2])], sep="") test_all(A)

結果:#39764236

自由欄

B - Call the ID NumberB - Call the ID Number

#39608819#39608819

C - Make Takahashi Happy

やってみよう!

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

test_dataC = [ { "in":"""3 3 3 2 2 2 1 3 1 5 4 """, "out": """3 """ },{ "in":"""10 10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 """, "out": """48620 """ }, ] def C(): H, W = map(int, input().split()) A = [list(map(int, input().split())) for _ in range(H)] ans = 0 print(ans) test_all(C)

自由欄

コンテスト中

コンテスト中の提出はこんな感じ。
始点から終点までの経路を「全ての移動($MOVE_0, MOVE_1, \dots, MOVE_i, \dots, MOVE_{H + W - 1}$)のうち下に移動する$i$の組み合わせ」で全探索します。

from itertools import combinations def C(): H, W = map(int, input().split()) A = [list(map(int, input().split())) for _ in range(H)] ans = 0 for com in combinations(range(H + W - 2), r=H - 1): route = [True] * (H + W - 2) for c in com: route[c] = False h = 0 w = 0 numbers = set([A[h][w]]) for nxt in route: if nxt: w += 1 else: h += 1 numbers.add(A[h][w]) if len(numbers) == H + W - 1: ans += 1 # print(numbers) print(ans) test_all(C)

結果:#39618916

自由欄

振り返り

上の実装でもまぁまぁいいと思うんですが、強いて挙げると移動のroute配列を作る処理(9, 10行目)がなんか野暮ったいです。
他の人の提出を見ると再帰DFSが多かったので、再帰しないループDFSで実装してみたのが以下。

これならルートの途中で「嬉しくない」ことが分かれば以降の探索を省略できますね。

def C(): H, W = map(int, input().split()) A = [list(map(int, input().split())) for _ in range(H)] nums = [None] * (H + W - 1) ans = 0 st = [(0, 0)] while st: h, w = st.pop() if A[h][w] in nums[:h + w]: continue nums[h + w] = A[h][w] if h + w == H + W - 2: ans += 1 else: if h < H - 1: st.append((h + 1, w)) if w < W - 1: st.append((h, w + 1)) print(ans) test_all(C)

結果:#39772336

自由欄

D - Tying RopeD - Tying Rope

やってみよう!

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

test_dataD = [ { "in":"""5 3 3 R 5 B 5 R 3 B 4 R 2 B """, "out": """1 2 """ },{ "in":"""7 0 """, "out": """0 7 """ },{ "in":"""7 6 5 R 3 R 7 R 4 R 4 B 1 R 2 R 3 B 2 B 5 B 1 B 7 B """, "out": """2 1 """ }, ] def D(): pass test_all(D)

自由欄

コンテスト中

連結成分、サイクル、と言えばもはやおなじみDSUですね。

from collections import defaultdict class DSU(): def __init__(self, n=None): self.dsu = defaultdict(lambda: -1) if n: for i in range(n): self.dsu[i] def leader(self, i): if self.dsu[i] < 0: return i self.dsu[i] = self.leader(self.dsu[i]) return self.dsu[i] def merge(self, i, j): '''サイズの大きい方(x)に小さい方(y)をマージ''' if i == j: return x = self.leader(i) y = self.leader(j) if x == y: return if self.dsu[x] > self.dsu[y]: x, y = y, x self.dsu[x] += self.dsu[y] self.dsu[y] = x def members(self, i): l = self.leader(i) return [k for k, v in self.dsu.items() if self.leader(k) == l] def __len__(self): return len([1 for v in self.dsu.values() if v < 0]) def D(): N, M = map(int, input().split()) dsu = DSU(N + 1) circle = 0 for _ in range(M): a, _, b, _ = input().split() a = int(a) b = int(b) if dsu.leader(a) == dsu.leader(b): circle += 1 else: dsu.merge(a, b) leaders = set() for i in range(1, N + 1): leaders.add(dsu.leader(i)) print(circle, len(leaders) - circle) test_all(D)

結果:#39622456

自由欄

E - Geometric Progression

やってみよう!

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

test_dataE = [ { "in":"""3 4 7 """, "out": """5 """ },{ "in":"""8 10 9 """, "out": """0 """ },{ "in":"""1000000000 1000000000000 998244353 """, "out": """919667211 """ }, ] def E(): pass test_all(E)

自由欄

振り返り

コンテスト中はうまく式変形できずに終了となりました。
「式変形」がどれぐらいのレベルだったかというと、等比数列の和の公式が分からない、というかこれが等比数列だということにも気付かないレベルでした...😇

という訳で!等比数列ですよ。

$$ \sum^{X - 1}_{i = 1}A^i = \frac{A^X - 1}{A - 1} $$

こんなん余裕やん!

def E(): A, X, M = map(int, input().split()) Ax = 1 Ae = A while X: if X & 1: Ax = Ax * Ae % M X >>= 1 Ae = Ae * Ae % M # print(Ax, pow(A - 1, -1, M)) print((Ax - 1) * pow(A - 1, -1, M) % M) test_all(E)

結果:#39787192

RE x 18 😭
なぜ・・・

自由欄

解説を見る①

kyopro_friendsさんの解説を見ます。

剰余の法$M$と互いに素とは限らない数$K$で除算を行いたい場合、$\bmod MK$で計算を行えばよい

上の提出では$A - 1$と$M$が互いに素でない場合にREとなっていたようです。

ところで「$\bmod MK$で計算」すればいいの理由が分かりません…🤔
と納得できずにググったら丁寧に解説されている方がいたのでまるっと引用します。
参照:【AtCoder】ABC293 のA,B,C,D,E における Python解説 - Qiita

$$ \begin{align*} & \frac{b}{a} \equiv q \pmod{p} \\[10pt] \Leftrightarrow \;& \frac{b}{a} = np + q \\[10pt] \Leftrightarrow \;& b = nap + aq \\[10pt] \Leftrightarrow \;& \bf{b \equiv aq \pmod{ap}} \\[10pt] \Leftrightarrow \;& \bf{q = \frac{b \pmod{ap}}{a}} \\[10pt] \Leftrightarrow \;& \bf{\frac{b}{a}\pmod{p} = \frac{b \pmod{ap}}{a}} \\[10pt] \end{align*}\\ $$

なるほど、天才か。
そしてpow関数を使えば繰り返し2乗法をする必要すらないとは…
という訳で以下解説のまんま。

def E(): A, X, M = map(int, input().split()) print(X % M if A == 1 else (pow(A, X, M * (A - 1)) - 1) // (A - 1) % M) test_all(E)

結果:#39831846

自由欄

解説を見る②

Kazu1998kさんの解説shakayamiさんの解説を見ます。

コンテスト中はなんとなくこんなことを想定して考えてました。
と言っても、再帰まで思い至らない時点で後出し知ったかぶりが見苦しいですね…

という訳で2つの解説をまとめると以下のような感じです。

$$ f(A, X) := \sum^{X-1}_{i=0}A^iとおく。\\ \begin{align*} f(A, X) \:\:\:=\:\:\: & \begin{cases} 1 & (X = 1)\\ f(A, X-1) + A^{X-1} & (X \ge 3, X: odd)\\ (1 + A^{\frac{X}{2}})f(A, \frac{X}{2}) & (X: even) \end{cases} & (1)\\ または、\\ f(A, X) \:\:\:=\:\:\: & \begin{cases} 1 & (X = 1)\\ 1 + A f(A, X-1) & (X \ge 3, X: odd)\\ (1 + A)f(A^2, \frac{X}{2}) & (X: even) \end{cases} & (2)\\ \end{align*} $$

以下、自分なりに咀嚼してコーディングしてみましたが、結局解説 by shakayamiの実装例通りになってしまいました。
せめてオリジナリティを出そうとpow関数的なヤツを自作してみましたが、特に意味はありません😇

from functools import lru_cache @lru_cache(None) def exp(base, e, M): if e == 1: return base ret = base if e & 1 else 1 e >>= 1 cnt = 2 while e: if e & 1: ret = ret * exp(base, cnt // 2, M) ** 2 % M e >>= 1 cnt *= 2 return ret % M def f1(a, x, M): if x == 1: return 1 % M elif x % 2: return (f1(a, x - 1, M) + exp(a, x - 1, M)) % M else: return ((1 + exp(a, x // 2, M)) * f1(a, x // 2, M)) % M def f2(a, x, M): if x == 1: return 1 % M elif x % 2: return (1 + a * f2(a, x - 1, M)) % M else: return (1 + a) * f2(a * a % M, x // 2, M) % M

(1)の場合

def E(): A, X, M = map(int, input().split()) print(f1(A, X, M)) test_all(E)

結果:#39834986

(2)の場合

def E(): A, X, M = map(int, input().split()) print(f2(A, X, M)) test_all(E)

結果:#39834989

自由欄

自由欄