2021-03-06
【Python】ABC194 解説
ABC194に参加しました. 結果は完位パフォーマンス!!.
今回はA~C問題がいつもより難しくてびっくりしました.
以下, A~F問題の解説およびPython解答例です.
A - I Scream
問題文が難しすぎる…
きちんと読めれば、題意のままに実装するだけ。
A, B = map(int, input().split())
C = A + B
if C >= 15 and B >= 8:
ans = 1
elif C >= 10 and B >= 3:
ans = 2
elif C >= 3:
ans = 3
else:
ans = 4
print(ans)
B - Job Assignment
仕事と仕事に割り当てる従業員の組み合せを全探索する。
同一人物を割り当てたときは終了時間の算出式が変わる。
N = int(input())
AB = [tuple(map(int, input().split())) for _ in range(N)]
ans = float('inf')
for i in range(N):
ai, bi = AB[i]
for j in range(N):
aj, bj = AB[j]
time = ai + bj if i == j else max(ai, bj)
ans = min(ans, time)
print(ans)
C - Squared Error
難しくてびっくりしちゃった。
DやEよりも時間を要した。。
考え方は以下。
- を左から順に見ていく。
- n とすると、すべてのについて を計算すればよい。
- 計算量は、が種類存在するとき程度。
from collections import Counter
N = int(input())
A = map(int, input().split())
C = Counter()
ans = 0
for a in A:
for k, v in C.items():
ans += v * ((k - a) ** 2)
C[a] += 1
print(ans)
D - Journey
確率漸化式の典型のような問題。
- 連結成分数がのときの期待値をとおく。求めたいのはであり、である。
- 個が連結しているとき、次の操作で連結済みの頂点が選ばれる確率を、未連結の頂点が選ばれる確率をとすると、これらは以下のように求められる。
- そして、との間には以下の漸化式が成り立つ。
右 辺第一項は連結済みの頂点を選んだ場合、第二項は未連結の頂点を選んだ場合である。
- 式を変形すると、以下の式となるため、を順に計算していけばよい。
N = int(input())
f = 0
for n in range(N - 1, 0, -1):
Ps, Pt = n / N, (N - n) / N
f = (Ps + (f + 1) * Pt) / (1 - Ps)
print(f)
E - Mex Min
Segment Tree
を利用して解いた。
実行時間制限がなんだね。。他にもっと厳しい問題があるので、そっちでも緩和お願いします。
- 数列を左から順に見ていく。
- とする。
- まず、を求めるには、以下の条件を満たす長さの数列の要素の最小値を求めれば良い。
数値がに存在するとき、
存在しない時、
(ただし, )
- Seg木を用いればこの問合せ処理はである。
- そして、については、Seg木を更新すればよい。更新内容はを削除・
を追加である。削除については、Counter
を利用して中の要素数がになるかどうかを管理する。
from collections import Counter
class SegmentTree():
"""割愛
"""
N, M = map(int, input().split())
A = list(map(int, input().split()))
INF = max(A) + 1
C = Counter() # C: {Ai, ..., A_i+M-1} に含まれる数値とその個数
st = SegmentTree([i for i in range(N)], min, INF)
# i = 0 での初期 化処理
for i in range(M):
a = A[i]
C[a] += 1
st.update(a, INF) # 数値が存在するときは INF として更新
ans = st.get(0, N) # i = 0 のときのmex
for i in range(1, N - M + 1): # i = 1, ..., N-M+1 まで順に見ていく
a_del = A[i - 1] # a_del: 削除する数値
C[a_del] -= 1
if C[a_del] == 0: # カウントが0のときのみseg木を更新
st.update(a_del, a_del)
a_add = A[i + M - 1] # a_add: 追加する数値
C[a_add] += 1
if C[a_add] == 1: # 新しく追加された場合のみseg木を更新。ちょっとした高速化。
st.update(a_add, INF)
ans = min(ans, st.get(0, N))
print(ans)
## F - Digits Paradise in Hexadecimal 解説AC。
桁DP
は検討したけど、計算量を減らす工夫がまったく思いつかなかった。。。
思いついたとしても、例外の考慮事項が多すぎて実装がかなり難しい。
MOD = 10 ** 9 + 7
N, K = input().split()
K = int(K)
L = len(N)
'''
dp[i][j]: 以下の条件を全て満たす数値の数
- N未満
- 「上位0~i桁がすべて0」ではない
'''
dp = [[0] * (K + 1) for _ in range(L + 1)]
C = set()
for i, n in enumerate(N):
crt, nxt = dp[i], dp[i + 1]
n = int(n, 16)
# dpテーブル内での遷移
for j in range(K + 1):
here = crt[j]
# 既に登場したj種類の数字を使う場合
nxt[j] += here * j
nxt[j] %= MOD
# これまでに登場していない数字を使う場合
if j < K:
nxt[j + 1] += here * (16 - j)
nxt[j + 1] %= MOD
# 「i - 1桁目 まで N と同じ」数値の考慮
for j in range(i == 0, n):
nj = len(C) + (j not in C)
if nj <= K:
nxt[nj] += 1
# i - 1 桁目まで all 0 の数値の考慮
if i > 0:
nxt[1] += 15
C.add(n)
cnt = dp[L][K]
cnt += (len(set(N)) == K) # N自身の考慮
print(cnt % MOD)
まとめ
早解きに助けられた!
関連記事最新記事
2021-05-09【Python】AtCoder - 30代社会人が始めて1年半で青色になりました
2021-04-12【Python】ABC198 解説
2021-03-27【Python】ABC197 解説
2021-03-20【Python】ABC196 解説
2021-03-13【Python】ABC195 パナソニックプログラミングコンテスト 解説