2
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?

[ABC427] ABC 427(Atcoder Beginner Contest)のA~D(A,B,C,D)問題をPythonで解説(復習)

Posted at

[ABC427] ABC 427(Atcoder Beginner Contest)のA~D(A,B,C,D)問題をPythonで解説(復習)

A問題

  • スライスを使って、左側と右側をくっつける。
A.py
"""
<方針>
- スライスを使って、左側と右側をくっつける。
"""
# 入力
S = input()

# 長さ
N = len(S)

# 左右
left = S[:N//2]
right = S[-N//2 + 1:]

# くっつける
ans = left + right

# 出力
print(ans)

B問題

  • A を配列で管理し、順番に求めていく。
  • 関数 f を用意しておく。
  • 二重の for 文を使う。
B.py
"""
<方針>
- `A` を配列で管理し、順番に求めていく。
- 関数 `f` を用意しておく。
- 二重の `for` 文を使う。
"""
# 関数
def f(a:int):
  ans = 0
  for val in str(a):
    ans += int(val)
  return ans

# 入力
N = int(input())

# 配列管理
A = [1]*(N)

# 二重ループ
for i in range(N-1):
  for j in range(i+1):
    # たす
    A[i+1] += f(A[j])

# 最後を出力
print(A[-1])

C問題

方針

  • N は小さいが、M は bit 全探索できるほど小さくない。
  • そこでまず、どのような黒白のパターンがあるかを全探索する。
  • その上で、それを成立させられるように辺を切ってみれば良い。
  • 一番辺を切った回数が少ないところを選べば良い。
  • 全体として、O(2^N・M) となる。

前提

  • C問題あたりで,TLEになる人は,制約条件を見る癖をつけよう.
  • AB問題では,基本的に制約条件を見ずにやっても解ける.
  • しかし,C問題以降では,制約条件を見ないと必ずTLEすると思っても良い.
  • 詳しい話は私の352回の記事C問題の解説に記したので,是非参照してほしい.
C.py
"""
<方針>
- `N` は小さいが、`M` は bit 全探索できるほど小さくない。
- そこでまず、どのような黒白のパターンがあるかを全探索する。
- その上で、それを成立させられるように辺を切ってみれば良い。
- 一番辺を切った回数が少ないところを選べば良い。
- 全体として、`O(2^N・M)` となる。
"""

# 双方向グラフ構築。
N, M = map(int, input().split())
E = [[False]*N for _ in range(N)]
for _ in range(M):
  u, v = map(int, input().split())
  u -= 1
  v -= 1
  E[u][v] = True
  E[v][u] = True

# 最小削除数
ans = float("inf")

# 黒白全パターン
for b in range(1<<N):
  
  # 黒いところを保存する。
  black = [False]*N
  for bit in range(N):
    if(b>>bit & 1):
      black[bit] = True
  
  # 削除回数
  tmp = 0
  for u in range(N):
    for v in range(N):
      # 辺がつながっている & 色が同じ
      if(E[u][v] and (black[u] == black[v])):
        tmp += 1
  
  # 双方向でカウントしたので、半分にしておく。
  tmp //= 2
  
  # 更新する
  ans = min(ans, tmp)

# 出力
print(ans)

D問題

  • dp[u][k] を考える。
    • u: 頂点
    • k: 状態
      • 0: 初期
      • 1: 最初の Alice の手が終わった後
      • 2: 最初の Bob の手が終わった後
      • ...
      • -1: 最後の Bob の手が終わった後
    • value: Alice が勝てるかどうか
  • この dp において、後ろから順番に、
    • Alice はひたすら True に遷移できるか。
    • Bob はひたすら False に遷移できるか。
  • 最後の手は S から生成してやれば上手くいきそう。
D.py
"""
<方針>
- `dp[u][k]` を考える。
  - `u`: 頂点
  - `k`: 状態
    - `0`: 初期
    - `1`: 最初の `Alice` の手が終わった後
    - `2`: 最初の `Bob` の手が終わった後
    - ...
    - `-1`: 最後の `Bob` の手が終わった後
  - `value`: `Alice` が勝てるかどうか
- この `dp` において、後ろから順番に、
  - `Alice` はひたすら `True` に遷移できるか。
  - `Bob` はひたすら `False` に遷移できるか。
- 最後の手は `S` から生成してやれば上手くいきそう。
"""
T = int(input())
for _ in range(T):
  # 入力
  N, M, K = map(int, input().split())
  S = input()
  E = [[] for _ in range(N)]
  for _ in range(M):
    U, V = map(int, input().split())
    U -= 1
    V -= 1
    E[U].append(V)
  
  # dp の初期値
  dp = [[False]*N for _ in range(2*K + 1)]
  for i, s in enumerate(S):
    if(s == "A"):
      dp[-1][i] = True
  
  # dp の遷移
  for i in range(K):
    # Bobの手
    for u in range(N):
      value = True # Bob はなんとか False にしたい
      for v in E[u]:
        if not (dp[-2*i - 1][v]):
          value = False
          break
      dp[-2*i - 2][u] = value
    
    # Aliceの手
    for u in range(N):
      value = False # Alice はなんとか True にしたい
      for v in E[u]:
        if(dp[-2*i - 2][v]):
          value = True
          break
      dp[-2*i - 3][u] = value
  
  # 頂点1は、最後から見て2*K個前の手において、最適に動いたら、どっちが勝つか。
  if(dp[0][0]):
    print("Alice")
  else:
    print("Bob")

補足

関係するリンク(参考文献など)

筆者について

その他

  • 間違いを含んでいる可能性があります.
  • 方針と言いつつ,方針ではない感想などを書いている可能性があります.
  • A問題から解説がだんだん省略されます.
  • コードに書かれている解説の文言と,その上に書いてある解説の文言を変えている場合があります.

最後に一言

  • 自称デンジ
2
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
2
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?