Atcoder - ABC342 A - E まで復習解説
ABC342 A - E を復習してまとめてみました。初学者の方の参考になれば幸いです。
A - Yay!
問題文
英小文字からなる文字列が与えられます。ここで S の長さは S 以上 3 以下です。 100
はある S 文字を除いて全て同じ文字で構成されています。 1
他のどの文字とも異なる文字は前から何文字目でしょうか。
Python では count
method を用いることで文字列中にある文字
そこで文字列 count
が
S = input()
for i, c in enumerate(S, start=1):
if S.count(c) == 1:
print(i)
B - Which is ahead?
または
後者のコードは以下のようになります。
N = int(input())
P = list(map(int, input().split()))
X = [0] * (N + 1)
for i, p in enumerate(P):
X[p] = i
Q = int(input())
for _ in range(Q):
a, b = map(int, input().split())
if X[a] < X[b]:
print(a)
else:
print(b)
C - Many Replacement
何度も
計算量が一番最悪なパターンは
そこで、毎回愚直に反映するのをやめて「現在
最後に
計算量は途中の
アルファベット 26 文字の列挙は手入力し TYPO をして WA をしてしまうともったいないので string.ascii_lowercase
を用いるとよいです。
N: Final = int(input())
S = input()
X = {c: c for c in string.ascii_lowercase}
Q = int(input())
for _ in range(Q):
c, d = input().split()
for k, v in X.items():
if v == c:
X[k] = d
T = []
for s in S:
T.append(X[s])
ans = "".join(T)
print(ans)
D - Square Pair
まずはノートに入力例1、2のケースや計算量
N = 8
A = list(map(int, "2 2 4 6 3 100 100 25".split(" ")))
print(f"{N=}")
print(f"{A=}")
X = [i * i for i in range(101)]
for i in range(N):
for j in range(i + 1, N):
if A[i] * A[j] in X:
print(f"{i=}, {j=}, {A[i]=}, {A[j]=}")
N=8
A=[2, 2, 4, 6, 3, 100, 100, 25]
i=0, j=1, A[i]=2, A[j]=2
i=2, j=5, A[i]=4, A[j]=100
i=2, j=6, A[i]=4, A[j]=100
i=2, j=7, A[i]=4, A[j]=25
i=5, j=6, A[i]=100, A[j]=100
i=5, j=7, A[i]=100, A[j]=25
i=6, j=7, A[i]=100, A[j]=25
そうすると
- どちらかが
だと積が0 =0 になるので平方数となる0^{2} - すでに平方数同士の値は積も平方数となる
- 平方数同士でないものも
など同じ数字同士をかけると平方数となる2 × 2 - また
なども平方数となる2 × 8
ということがわかってきました。特に最後の情報から
- 素因数分解して奇数となる素数が等しければ (つまり
の場合など)、それらは同じ値とみなせる2 = 2^{1}, 8 = 2^{3}
といえます。
以上のことから、各
求める答えは
-
の時、以下の2通りv = B[0] -
から0 つ選ぶ:2 {}_v C_2 -
から0 つ選び、残り1 から選ぶ:N - v v × (N - v)
-
-
の時、以下の1通りv = B[0以外の値] -
からx つ選ぶ:2 {}_v C_2
-
となります。
少し込み入った計算をするためか計算量が高いため Python では TLE となってしまいます。 PyPy で提出しましょう。
from collections import defaultdict
N = int(input())
A = list(map(int, input().split()))
def prime_factors(N):
v = N
p = defaultdict(int)
for i in range(2, N):
if i * i > N:
break
while v % i == 0:
p[i] += 1
v //= i
if v != 1:
p[v] += 1
return p
# 素因数分解して奇数個の素数だけ残してグループにする各グループの NC2 の和が答え
# 0 だけ特別扱いする
B = defaultdict(int)
for a in A:
factors_ = prime_factors(a)
# 各因数を 2 で割る
factors = {}
for k, v in factors_.items():
if v % 2 == 1:
factors[k] = 1
# Python は dict はキーにできないので tuple に変換する
B[tuple(sorted(factors.items()))] += 1
ans = 0
for k, v in B.items():
if k == ((0, 1),):
# 0 は他のすべての値とペアになる
ans += v * (v - 1) // 2 + v * (N - v)
else:
# それ以外はそのまま NC2
ans += v * (v - 1) // 2
print(ans)
E - Last Train
経路探索の問題です。ダイクストラ法を使う場合はある点
そこで、電車の路線がすべて逆に向かっているとしましょう。すなわち
「負の値を含まないこと」という制約がダイクストラ法を学ぶ時に出てくると思いますが、この制約はあくまで経路のコストが負と正のものが同時に存在すると閉路をグルグル回れば回るほどコストが減るみたいな経路が存在する場合正しい解を得られないことがあるのが問題でした。
今回の場合、もともとすべてコストは正であるため、逆に考えた場合のコストはすべて負であり、求めるものは最もコストが大きくなるものであり、コストと求めたいものがすべて逆になっているため問題なくダイクストラ法が利用できます。
そこでヒープキューに
その駅から乗ることのできる路線を入れる際に、その路線の何番目に発車する電車に乗るべきかもついでに考える必要があります。
- 到着予定時刻より後にその路線の始発電車が出る場合:その路線を利用することはできない
- 到着予定時刻より前にその路線の終発電車が出る場合:終発電車にのり移動後到着予定時刻まで待機する
- それ以外:可能な限り遅い電車に乗りたい。
を(到着予定時刻 - l - c) で割ることでどの電車に乗ればよいかわかるd
と場合分けをしましょう。
import heapq
N, M = map(int, input().split())
G = [[] for _ in range(N)]
trains = []
for i in range(M):
l, d, k, c, a, b = map(int, input().split())
a, b = a - 1, b - 1
trains.append((l, d, k, c, a, b))
G[b].append(i)
INF = float("inf")
dist = [INF] * N
# N - 1 を探索済みとみなすために INF より小さいが、得られる答えより大きな値を入れておく
dist[-1] = 10**18
queue = []
for i in range(M):
# N - 1 と別の駅をつないでいる路線で、その路線番号と最終列車の出発時刻を queue に追加
l, d, k, c, a, b = trains[i]
if b == N - 1:
queue.append((-(l + (k - 1) * d), i))
heapq.heapify(queue)
while queue:
time, i = heapq.heappop(queue)
time *= -1
l_, d_, k_, c_, a, b_ = trains[i]
if dist[a] != INF:
continue
dist[a] = time
# 駅 a から利用できる路線を利用できるのであれば queue に追加
for j in G[a]:
l, d, k, c, na, _ = trains[j]
# すでに探索済みか N であればスキップ
if dist[na] != INF:
continue
"""
路線 j の何番目の電車に乗るべきか調べる
time - l - c が非常に大きい場合は最終列車に乗ればよく、time - l - c が負の場合はどの列車も乗れない
"""
v = min((time - l - c) // d, k - 1)
if 0 <= v:
# 路線 j の v 番目の電車に乗る
new_time = l + v * d
heapq.heappush(queue, (-new_time, j))
for d in dist[: N - 1]:
if d == INF:
print("Unreachable")
else:
print(d)
Discussion