振り返りです。

UNIQUE VISION Programming Contest 2023 Spring(AtCoder Beginner Contest 300) - 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)

C - Cross

やってみよう!

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

test_dataC = [ { "in":"""5 9 #.#.#...# .#...#.#. #.#...#.. .....#.#. ....#...# """, "out": """1 1 0 0 0 """ },{ "in":"""3 3 ... ... ... """, "out": """0 0 0 """ },{ "in":"""3 16 #.#.....#.#..#.# .#.......#....#. #.#.....#.#..#.# """, "out": """3 0 0 """ },{ "in":"""15 20 #.#..#.............# .#....#....#.#....#. #.#....#....#....#.. ........#..#.#..#... #.....#..#.....#.... .#...#....#...#..#.# ..#.#......#.#....#. ...#........#....#.# ..#.#......#.#...... .#...#....#...#..... #.....#..#.....#.... ........#.......#... #.#....#....#.#..#.. .#....#......#....#. #.#..#......#.#....# """, "out": """5 0 1 0 0 0 1 0 0 0 0 0 0 0 0 """ }, ] def C(): pass test_all(C)

自由欄

コンテスト中にやりたかったこと

「1行目から見て行って、✕があれば数えながら消していけばいんじゃね?」という単純な考えのもと実装していったのはいいものの、結局うまく落とし込めずWA x 3の末にタイムアップとなった回でした・・・

振り返ってみると、✕の中の✕を考慮できてなかっただけのアホでした。
という訳で、やりたかったのは以下みたいな感じ。

def C(): from collections import defaultdict H, W = map(int, input().split()) C = [list(input()) for _ in range(H)] ans = defaultdict(int) for h in range(H): left_top = [] for w in range(W): if C[h][w] == "#": if w < W - 1 and C[h + 1][w + 1] == "#": left_top.append(w) else: lt = left_top.pop() n = (w - lt) // 2 ans[n] += 1 size = n * 2 + 1 for i in range(size): C[h + i][lt + i] = "." C[h + i][w - i] = "." print(*[ans[n] for n in range(1, min(H, W) + 1)]) test_all(C)

結果:#42736227

自由欄

振り返り

BFSでやるとこんな感じ。
解説 by evimaではDFSでスッキリ書けてて負けた感がすごい😇

def C(): from collections import defaultdict, deque from itertools import product H, W = map(int, input().split()) C = [input() for _ in range(H)] ans = defaultdict(int) seen = set() for h, w in product(range(H), range(W)): if (h, w) in seen: continue seen.add((h, w)) if C[h][w] == ".": continue q = deque([(h, w)]) n = 0 while q: h, w = q.popleft() n += 1 for i, x in [(h + a, w + b) for a, b in product([1, -1], repeat=2)]: if 0 <= i <= H - 1 and 0 <= x <= W - 1 and (i, x) not in seen: seen.add((i, x)) if C[i][x] == "#": q.append((i, x)) ans[(n - 1) // 4] += 1 print(*[ans[i] for i in range(1, min(H, W) + 1)]) test_all(C)

結果:#42716480

自由欄

D - AABCC

やってみよう!

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

test_dataD = [ { "in":"""1000 """, "out": """3 """ },{ "in":"""1000000000000 """, "out": """2817785 """ }, ] def D(): pass test_all(D)

自由欄

try

せっかくなのでやってみます。
枝刈り大事。

def D(): from bisect import bisect_left N = int(input()) f_max = int((N / 12) ** (1/2)) + 1 seed = [1] * (f_max + 1) for i in range(3, f_max + 1, 2): if not seed[i]: continue for j in range(i * 2, f_max + 1, i): seed[j] = 0 facs = [2] for i in range(3, f_max + 1, 2): if seed[i]: facs.append(i) ans = 0 for i in range(len(facs) - 2): if facs[i] ** 2 * facs[i + 1] * facs[i + 2] ** 2 > N: break for j in range(i + 1, len(facs) - 1): a2b = facs[i] ** 2 * facs[j] idx = bisect_left(facs, (N / a2b) ** (1/2)) if idx <= j: break elif idx >= len(facs): ans += len(facs) - 1 - j elif a2b * facs[idx] ** 2 == N: ans += idx - j else: ans += idx - j - 1 print(ans) test_all(D)

結果:#42888284

自由欄

E - Dice Product 3

やってみよう!

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

test_dataE = [ { "in":"""6 """, "out": """239578645 """ },{ "in":"""7 """, "out": """0 """ },{ "in":"""300 """, "out": """183676961 """ },{ "in":"""979552051200000000 """, "out": """812376310 """ }, ] def E(): pass test_all(E)

自由欄

try

せっかくなのでやってみます。

一旦MODのことは忘れて例題1を手計算してみます。

  • (6) : $\frac{1}{6}$
  • (2, 3), (3, 2) : $\frac{1}{18}$

さらに以下のパターンでは等比級数になるので、

  • (2, 1, 3), (2, 1, 1, 3)... : $\frac{1}{18} \times (\frac{1}{6} + \frac{1}{6 ^ 2} + \frac{1}{6 ^ 3} + ... + \frac{1}{6 ^ \infty}) = \frac{1}{18} \times \frac{1}{5}$

合計$\frac{7}{30}$になります。
加えて、最初に1が1回以上連続して上のパターンを辿る確率も同様に等比級数になるので、結果として $$ \big(1 + \frac{1}{5}\big) \times \frac{7}{30} = \frac{7}{25} $$

になるという訳ですね。
はい、そもそも確率だすのがムズい。

この手計算の段階でだいぶ時間掛かってんのに、実装に落とし込むってなったらどないせいっちゅうねん😡
という訳で解説をみます。曰く、

dp(n) : (持っている数がnである状態からスタートしたときに, 最終的に持っている数がNに一致する確率)と定義すると、答えはdp(1)

そしてdp(n)は以下のようになるとのこと。

$$ \begin{align} & DP(n) = \frac{1}{6}\big(DP(n) + DP(2n) + DP(3n) + DP(4n) + DP(5n) + DP(6n)\big)\\ \Leftrightarrow \:& \frac{5}{6}DP(n) = \frac{1}{6}\big(DP(2n) + DP(3n) + DP(4n) + DP(5n) + DP(6n)\big)\\ \Leftrightarrow \:& DP(n) = \frac{1}{5}\big(DP(2n) + DP(3n) + DP(4n) + DP(5n) + DP(6n)\big)\\ \end{align} $$

あれ、手計算で手こずった1が出る場合のパターンがキレイに消えとる…
そしてめっちゃ簡単そうな再帰呼び出しになりました。実装するとこんな感じ。
ちなみに期待値のMODについてはABC280のE問題でばっちり理解した通りpow関数で一発です(理解したとは言ってない)✌

def E(): from functools import lru_cache MOD = 998244353 N = int(input()) @lru_cache(None) def dp(n): if n > N: return 0 elif n == N: return 1 else: return sum(dp(i * n) for i in range(2, 7)) * pow(5, -1, MOD) % MOD print(dp(1)) test(E, test_dataE[0]) test_all(E)

結果:#42947625

自由欄

自由欄