2021-01-23
【Python】ABC189 解説
ABC189に参加しました. 結果は完位パフォーマン ス…
泣きたい
以下, A~F問題の解説およびPython解答例です.
2021/01/24 F問題の解説を追加
A - Slot
set
の大きさで判定する。
C = set(input())
ans = 'Won' if len(C) == 1 else 'Lost'
print(ans)
B - Alcoholic
小数の扱いに注意。
全体にをかけて整数の範囲で判定できるようにする。
N, X = map(int, input().split())
IN = [tuple(map(int, input().split())) for _ in range(N)]
x = 0
for i, (v, p) in enumerate(IN):
x += v * p
if x > 100 * X:
ans = i + 1
break
else:
ans = -1
print(ans)
C - Mandarin Orange
解けなかった。。泣きたい。
は間に合わないと勘違いしてた。
N = int(input())
A = list(map(int, input().split()))
INF = float('inf')
ans = 0
for l in range(N):
m = INF
for r in range(l, N):
m = min(m, A[r])
cnt = (r - l + 1) * m
ans = max(ans, cnt)
print(ans)
D - Logical Expression
メモ化再帰
で解いた。
- : とする。 である。
- 求めたい答えはである。また, 初期条件は である。
と表すことができ, との値に応じて係数を求めればよい。
- 例えば, のときは,
となるは通り
となるは通り
よって, である。
import sys
sys.setrecursionlimit(10 ** 6)
def dfs(i, j):
global N
if (i, j) not in memo:
if i == 0:
ret = 1
else:
zero, one = dfs(i - 1, 0), dfs(i - 1, 1)
if j == 0:
if P[i - 1] == 'AND':
ret = one + 2 * zero
else:
ret = zero
else:
if P[i - 1] == 'AND':
ret = one
else:
ret = 2 * one + zero
memo[(i, j)] = ret
return memo[(i, j)]
N = int(input())
P = [input() for _ in range(N)]
memo = {}
ans = dfs(N, 1)
print(ans)
E - Rotate and Flip
行列計算があったのでNumpy
を使って実装したら4問ほど…
Pypy
に書き直す時間はなく撃沈。もったいなかった…
次の機会に向けて行列まわりのライブラリを作っておこうかな
- 各操作は以下のように行列で表すことができる。
操作: ,
操作:
操作: ,
操作:
- とする。
によりを事前計算しておく。
- すると点の回目の操作後の座標は以下の式により求められる。
import sys
def mul(S, sizeS, T, sizeT):
''' 行列積 S @ T を計算する
S, T: 1次元行列
sizeS, sizeT: [row数, col数]
Sc == Tr 必須
Returns: [Sr, Tc]の1次元行列
'''
Sr, Sc, Tr, Tc = *sizeS, *sizeT
N = Sr * Tc
ret = [0] * (N)
for i in range(N):
x, y = divmod(i, Tc)
L = S[Sc * x: Sc * (x + 1)]
R = [T[Tc * j + y] for j in range(Tr)]
tmp = sum(a * b for a, b in zip(L, R))
ret[i] = tmp
return ret
N = int(input())
P = [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
M = int(input())
OP = [tuple(map(int, sys.stdin.readline().split())) for _ in range(M)]
Q = int(input())
query = [tuple(map(int, sys.stdin.readline().split())) for _ in range(Q)]
op1 = [0, 1, 0, -1, 0, 0, 0, 0, 1]
op2 = [0, -1, 0, 1, 0, 0, 0, 0, 1]
op3 = [-1, 0, 0, 0, 1, 0, 0, 0, 1] # op3[2]に2pが入る
op4 = [1, 0, 0, 0, -1, 0, 0, 0, 1] # op4[5]に2pが入る
three = (3, 3)
one = (3, 1)
T = [None] * (M + 1)
T[0] = [1, 0, 0, 0, 1, 0, 0, 0, 1]
for i, op in enumerate(OP):
j = op[0]
if j == 1:
S = op1
elif j == 2:
S = op2
elif j == 3:
S = op3
S[2] = 2 * op[1]
else:
S = op4
S[5] = 2 * op[1]
T[i + 1] = mul(S, three, T[i], three)
for a, b in query:
b -= 1
z = P[b] + [1]
tmp = mul(T[a], three, z, one)
print(tmp[0], tmp[1])
F - Sugoroku2
解説AC。
考え方は以下の通り。
- とおく。
- 遷移は以下の式で表すことができる。
- ここで、を求めるのにの値が必要、という状態になり自己循環に陥ってしまう。
- そこで、 と置くと計算ができる。これはの式が必ず という次式の形となるため、最終的に以下の方程式を解けばよいからである。
- 「と置く」って、どうやってコーディングするの?と疑問をもつかもしれないが、Pythonであればのをプロパティにもつクラスを作ればよい。
class f():
'''
ax + b を表すクラス
和・差およびスカラー除算を定義する
'''
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
return f(self.a + other.a, self.b + other.b)
def __sub__(self, other):
return f(self.a - other.a, self.b - other.b)
def __truediv__(self, value):
return f(self.a / value, self.b / value)
N, M, K = map(int, input().split())
A = [0] * (N + 1)
for a in map(int, input().split()):
A[a] = 1
x = f(1, 0) # 1 * x + 0
zero = f(0, 0) # 0 * x + 0
one = f(0, 1) # 0 * x + 1
dp = [zero] * (N + M + 1)
S = zero # dp[i] + dp[i + 1] + ... + dp[i + M] の累積和
for i in range(N - 1, -1, -1):
if A[i]:
dp[i] = x
else:
dp[i] = S / M + one
S += dp[i]
S -= dp[i + M]
a, b = dp[0].a, dp[0].b
if a + pow(10, -6) > 1: # a == 1 のときはゴール不可。誤差を考慮して不等式で実装する。
print(-1)
else:
print(b / (1 - a))
まとめ
マジで落ち込む。。。
関連記事最新記事
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 パナソニックプログラミングコンテスト 解説