0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AtCoder ABC400 振り返り(緑コーダーがPythonでAB+CD問題)

Posted at

AtCoder Beginner Contest 400 振り返り

今回はABの2問解答でした。Bまでは順調に解けたのですが、C問題で数式変形がうまくできずに正解が求まらず...。D問題は幅優先探索が正着なところを、深さ優先探索で解こうとして解けず...。

C, D問題はコンテスト終了後に、復習して解きました。

またしてもレーティングが減ってしまい、そろそろ緑陥落が見えてまいりました(あと−30)。

A - ABC400 Party

400 で割り切れるかを判定しています。

A = int(input())

if 400 % A == 0:
    print(400 // A) 
else:
    print(-1)

B - Sum of Geometric Series

数式通りに計算していきました。Pythonだとオーバーフローを考えていなくて良いのが楽ですね。

N, M = map(int, input().split())

X = 0
for i in range(M+1):
    X += N ** i

    if X > 10 ** 9:
        print("inf")
        exit()

print(X)

C - 2^a b^2 (解説AC)

これは解説を見て解きました。

考え方としては...

  • a は 1 から 60 までループさせれば良い
  • b が偶数の場合、2 ^ a の項に統合してしまって良い
    • 2^2 * 6^2 → 2^4 * 3^2

なので、aをループさせて、そのa に対して条件を満たす B=1,3,5,7... の個数を求めれば良いということになる。

また、 他の方の解答を見ていて math.isqrt() を知りました。これだと平方根の整数部分だけが求められて、誤差が気にならなくなります。

N = int(input())

count = 0

for a in range(1, 61):
    A = 2 ** a
    if A > N:
        break

    B2 = N // A
    max_B = math.isqrt(B2)
    # 奇数だけカウント
    count += (max_B + 1) // 2

print(count)

D - Takahashi the Wall Breaker (解説AC)

壁を壊すパターンも含めて、幅優先探索を行えば良い。最短距離のものから処理したいので、通常は優先度付きキュー heapq を使用したいところですが、この問題では1問だけどうしてもTLEになってしまいます。

そこで、 01-BFS という手法を使うと良いとのことでした。これであれば deque を使えるので、より高速に処理することができます。

H, W = map(int, input().split())
S = [list("*" + input() + "*") for _ in range(H)]
S.insert(0, ["*"] * (W + 2))
S.append(["*"] * (W + 2))
A, B, C, D = map(int, input().split())

visited = [[INF] * (W + 2) for _ in range(H + 2)]
visited[A][B] = 0

# 幅優先探索
queue = deque()
queue.append((0, A, B))

while queue:
    break_count, x, y = queue.popleft()

    if x == C and y == D:
        break
    
    for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
        # 通路を進むパターン
        if S[x + dx][y + dy] == ".":
            if visited[x + dx][y + dy] > break_count:
                visited[x + dx][y + dy] = break_count
                # 現状の最短距離なので、キューの左側に追加
                queue.appendleft((break_count, x + dx, y + dy))
                continue

        # 壁を壊すパターン
        if S[x + dx][y + dy] == "#":
            # 1個目の壁
            if visited[x + dx][y + dy] > break_count + 1:
                visited[x + dx][y + dy] = break_count + 1
                # 壁を壊したので、キューの右側に追加
                queue.append((break_count + 1, x + dx, y + dy))

            # 2個目の壁を壊せれば壊す
            if 0 < x + dx*2 < W + 1 and 0 < y + dy*2 < H + 1:
                if S[x + dx*2][y + dy*2] == "#" or S[x + dx*2][y + dy*2] == ".":
                    if visited[x + dx*2][y + dy*2] > break_count + 1:
                        visited[x + dx*2][y + dy*2] = break_count + 1
                        # 壁を壊したので、キューの右側に追加
                        queue.append((break_count + 1, x + dx*2, y + dy*2))

print(visited[C][D])

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?