Atcoder - ABC340 A - E まで復習解説
ABC340 A - E を復習してまとめてみました。初学者の方の参考になれば幸いです。
A - Arithmetic Progression
問題文
初項が、末項が A 、公差が B であるような等差数列を出力してください。 D
Python の range
関数がちょうどいいです。 range(A, B + 1, D)
とすることで問題と同じ数列を出力することができます。 range
は開区間なので range(A, B, D)
とすると
A, B, D = map(int, input().split())
ans = list(range(A, B + 1, D))
print(*ans)
B - Append
こちらも Python のリストを用いると簡単に実装できます。まさに Python のリストの末尾に append
といいますね。
末尾から
Q: Final = int(input())
A = []
for _ in range(Q):
type_, x = map(int, input().split())
if type_ == 1:
A.append(x)
elif type_ == 2:
print(A[-x])
C - Divide and Divide
「
そこで、メモ化再帰をしましょう。
と、定義します。 Python は @cache
デコレータをつけると自動で
from functools import cache
@cache
def f(x):
# 整数 x を 処理するのに払う金額
if x == 1:
return 0
a = (x + 1) // 2
b = x // 2
return f(a) + f(b) + x
N = int(input())
ans = f(N)
print(ans)
D - Super Takahashi Bros.
各ステージからの移動経路が2パターンあるのですべての経路を調べていると計算量が
そこで DP かな?と思ったのですが、厄介なのが
(スーパーマリオブラザーズ2みたいに前に戻ってしまうワープがあるイメージでしょうか)
これでは単純に前から DP で値を更新することができません。例えば、本当は
そこで経路探索とみなしてダイクストラ法で解きましょう。ダイクストラ法だと heap queue
を用いることで、先に更新すべき値から順に計算を行ってくれます。2つの行動はどちらも
- ステージ
からステージi へi + 1 秒 かけて移動A_{i} - ステージ
からステージi へX_{i} 秒 かけて移動B_{i}
という経路とみなすことができます。
こうしてみるとダイクストラ法って自動でトポロジカルソートしている DP のようなものとみなすこともできますよね。奥が深いです。
import heapq
N = int(input())
G = [[] for _ in range(N)]
for i in range(N - 1):
a, b, x = map(int, input().split())
x -= 1
G[i].append((a, i + 1))
G[i].append((b, x))
def dijkstra(s):
# 始点sから各頂点への最短距離
d = [float("inf")] * N
used = [False] * N
d[s] = 0
used[s] = True
queue = []
for e in G[s]:
heapq.heappush(queue, e)
while queue:
min_edge = heapq.heappop(queue)
# まだ使われてない頂点の中から最小の距離のものを探す
if used[min_edge[1]]:
continue
v = min_edge[1]
d[v] = min_edge[0]
used[v] = True
for e in G[v]:
if not used[e[1]]:
heapq.heappush(queue, (e[0] + d[v], e[1]))
return d
dist = dijkstra(0)
ans = dist[-1]
print(ans)
E - Mancala 2
工夫しつつシミュレーションを実際に行うのが早そうです。環状になっているのが少しややこしいですが、箱
この時、愚直に順番に各箱に配ってしまうと
そこで Lazy Segment Tree を用います。 Lazy Segment Tree は一点更新や区間更新を高速に行うことができます。 Python の AtCoder 環境は公式の C++ ライブラリを Python に移植していただいている https://github.com/not522/ac-library-python がインストールされていますのでそのまま使えます。
from atcoder.lazysegtree import LazySegTree
def op(a, b):
return 0
e = 0
def mapping(a, b):
return a + b
def composition(a, b):
return a + b
id_ = 0
N, M = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))
segtree = LazySegTree(op, e, mapping, composition, id_, A)
for b in B:
balls = segtree.get(b)
# b から balls 個取り出す
segtree.set(b, 0)
# b + 1 から順に1個ずつ配る円形状に並んでいるので N - 1 の次は 0 になるように配る
div, mod = divmod(balls, N)
# 全部に div 個配り, b + 1 から b + mod までに1追加する
if div != 0:
segtree.apply(0, N, div)
if b + mod < N:
segtree.apply(b + 1, b + mod + 1, 1)
else:
segtree.apply(b + 1, N, 1)
segtree.apply(0, ((b + mod) % N) + 1, 1)
print(*[segtree.get(i) for i in range(N)])
なお、私はコンテスト中は op
, e
, mapping
, composition
の持ち方がイマイチ (区間和とかでググってもうまく例を見つけることができなかったです) & get
method に気づかず値を参照するのに prod(i, i + 1)
としていたためか TLE になってしまったので、 ChatGPT に質問しながら C++ で実装し直し AC しました。
Discussion