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

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

# A問題
- 偶数の時
  - `=` は `2` つ真ん中に入れる。左右それぞれに `-` を `N//2 - 1` つ入れる。
- 奇数の時
  - `=` は `1` つ真ん中に入れる。左右それぞれに `-` を `N//2` つ入れる。
```A.py
"""
<方針>
- 偶数の時
  - `=` は `2` つ真ん中に入れる。左右それぞれに `-` を `N//2 - 1` つ入れる。
- 奇数の時
  - `=` は `1` つ真ん中に入れる。左右それぞれに `-` を `N//2` つ入れる。
"""
# 入力
N = int(input())

# 偶数の時
if(N%2 == 0):
  left = right = "-" * (N//2 - 1)
  mid = "=" * 2
# 奇数の時
else:
  left = right = "-" * (N//2)
  mid = "=" * 1

# 出力
print(left + mid + right)
```

# B問題
- それぞれのカードが何枚あるかをカウントする。
- `3` 枚以上が `1` 種類以上存在し、`2` 枚以上が `2` 種類以上存在していれば、`Yes` 。
```B.py
"""
<方針>
- それぞれのカードが何枚あるかをカウントする。
- `3` 枚以上が `1` 種類以上存在し、`2` 枚以上が `2` 種類以上存在していれば、`Yes` 。
"""
# 入力
A = list(map(int, input().split()))

# カードの種類を管理
C = [0]*14

# カードの種類を集計
for a in A:
  C[a] += 1

# 3枚以上と2枚以上をカウント
cnt3 = 0 #3枚以上
cnt2 = 0 #2枚以上
for c in C:
  if(c>=3):
    cnt3 += 1
  if(c>=2):
    cnt2 += 1

# 判定
if(
  (cnt3 >= 1) and 
  (cnt2 >= 2)
  ):
    print("Yes")
else:
  print("No")
  

```

# C問題
## 方針
- `A` として存在しない値まで管理すると `O(A)` で到底間に合わない。
- 辞書 `di` を使うことで、`A` として存在する値だけにし、`O(N)` で間に合わせる。
- 線形走査を意識して処理をする。
## 前提
- `C`問題あたりで，`TLE`になる人は，制約条件を見る癖をつけよう．
- `A`と`B`問題では，基本的に制約条件を見ずにやっても解ける．
- しかし，`C`問題以降では，制約条件を見ないと必ず`TLE`すると思っても良い．
- 詳しい話は私の[352回の記事](https://qiita.com/mattsunkun/items/837444254f03e6105922) の`C`問題の解説に記したので，是非参照してほしい．
```C.py
"""
<方針>
- `A` として存在しない値まで管理すると `O(A)` で到底間に合わない。
- 辞書 `di` を使うことで、`A` として存在する値だけにし、`O(N)` で間に合わせる。
- 線形走査を意識して処理をする。
"""
from collections import defaultdict

N = int(input())
A = list(map(int, input().split()))

# 辞書
## key: Aの値
## val: Aの値の重複数
di = defaultdict(int)
for a in A:
  di[a] += 1

ma = 0 # 最大値
for ke, va in di.items():
  # 重複が無い時
  if(va == 1):
    # 最大値を更新
    ma = max(ma, ke)

# 最大値に合致する番号を見つける。
for i, a in enumerate(A):
  # 最大値合致したとき
  if(a == ma):
    # 番号を出力
    print(i+1)
    exit()

# 最大値が見つから無い時
print(-1)
```

# D問題
- 煙を `set` で管理し、焚き火と高橋君を移動させる。
```D.py
"""
<方針>
- 煙を `set` で管理し、焚き火と高橋君を移動させる。
"""
N, R, C = map(int, input().split())
S = input()

# 煙
se = set()

# 煙をsetに登録する関数
def id(y, x):
  return y*(N+1) + x

# <デバッグ用> setに登録されている煙の座標を取得
def deId(id):
  return divmod(id, (N+1))

# 焚き火の初期位置
y = x = 0

# 答え
ans = []

# 時間を進める
for s in S:
  # 風の方向を取得
  match s:
    case "N":
      dy = -1
      dx = 0
    case "W":
      dy = 0
      dx = -1
    case "S":
      dy = +1
      dx = 0
    case "E":
      dy = 0
      dx = +1
  
  # 高橋君を移動させる。
  R -= dy
  C -= dx
  
  # 煙を登録
  se.add(id(y, x))
  
  # 高橋君が煙とかぶっているかどうか。
  ans.append("1" if id(R, C) in se else "0")
  # print(y, x, R, C, list(map(deId, se)))
  
  # 焚き火を移動
  y -= dy
  x -= dx

# 出力
print("".join(ans))
```

# 補足
### 関係するリンク(参考文献など)
- [今回のコンテスト](https://atcoder.jp/contests/abc398)
### 筆者について
- [Atcoderアカウント](https://atcoder.jp/users/mattsunkun)
- *今回も不参加のため，成績なし．*
- [解説で示したA問題の提出](https://atcoder.jp/contests/abc398/submissions/64119907)
- [解説で示したB問題の提出](https://atcoder.jp/contests/abc398/submissions/64120116)
- [解説で示したC問題の提出](https://atcoder.jp/contests/abc398/submissions/64122109)
- [解説で示したD問題の提出](https://atcoder.jp/contests/abc398/submissions/64122881)
### その他
- **間違いを含んでいる可能性があります．**
- 方針と言いつつ，方針ではない感想などを書いている可能性があります．
- A問題から解説がだんだん省略されます．
- コードに書かれている解説の文言と，その上に書いてある解説の文言を変えている場合があります．
### 最後に一言
- AtCoderのDiffが確認できない...