AtCoder Beginner Contest 189をPythonで解く

投稿日:  更新日:2022/09/02

Atcoder Python

B!
Daniel AgreloによるPixabay(https://pixabay.com/)からの画像

こんにちは, Shinoryoです.

今回はAtCoder Beginner Contest 189を, Pythonで解いてみた結果を書き連ねていこうと思います.

A - Slot

愚直に条件を確認します. C1=C2かつC2=C3で大丈夫です.

# 入力
c = input()
# 一致判定
if c[0] == c[1] and c[1] == c[2]:
print("Won")
else:
print("Lost")

B - Alcoholic

お酒を1杯飲むたびに基準値を超えるかどうかを確認します. 今回入力は全て整数なので, アルコール等の量を100倍して計算することで, 整数の範囲で確実に計算することができます.

# 入力
# アルコールの量は100倍にして整数の範囲で計算する
n, x = [int(x) for x in input().split()]
x *= 100
# アルコール摂取量格納
alc = 0
# お酒を飲んでみる
for i in range(n):
v, p = [int(x) for x in input().split()]
alc += v * p
# 酔っ払っているか確認
if alc > x:
print(i + 1)
exit()
# 酔っ払っていない場合
print(-1)

C - Mandarin Orange

全探索で計算することを考えます. xとしてはAlからArまでで最も小さい値をとれば問題ありません. しかし, この方法だと時間計算量が非常に多く*1, TLE.

# 入力
n = int(input())
a = [int(x) for x in input().split()]
# 答えを格納
ans = 0
# 全探索するゾ
for l in range(n):
for r in range(l,n):
# xは可能な限り最大の値をとる
x = min(a[l:r+1])
# ansを更新
ans = max(ans, (r - l + 1)*x)
# 答えを出力
print(ans)

そこで, 固定されたlに対してrlからnまで順に大きくしながらxを更新していくという方法にすることによって, 時間計算量を減らすことができます*2. しかし, これでもTLEになってしまいます.

# 入力
n = int(input())
a = [int(x) for x in input().split()]
# 答えを格納
ans = 0
# 全探索するゾ
for l in range(n):
# 最初(r = l)のxはa[l]に一致する
x = a[l]
for r in range(l,n):
# rが増えていくたびにxの更新が入る
x = min(x, a[r])
# ansを更新
ans = max(ans, (r - l + 1)*x)
# 答えを出力
print(ans)

PyPy3だとACできたので, これ以上は踏み込みません.

D - Logical Expression

N60とはいえ全変数列を探索しようとすると大変な量になりますので, 工夫が必要です. ここでは, 動的計画法(dynamic programming)を用いて解くことを考えます.

簡単に, N=1の場合は以下のように考えられます.

  • S1ANDであるとすると, x1y0Trueでなければなりません. よって, (1)(x0,x1)=(True,True) のみが当てはまります.
  • S1ORであるとすると, x1y0のどちらかがTrueであればよいです. よって, (2)(x0,x1)=(True,True),(False,True),(True,False) のみが当てはまります.

これを一般化します. N=K2の場合は以下のように考えられます. 関数f(S1,S2,,SN)を, 文字列S1,S2,,SNに対する答え(すなわち, yNTrueであるような変数列(x0,x1,x2,,xN)の数)とします.

  • SKANDであるとすると, xKyK1Trueでなければなりません. よって, f(S1,S2,,SK)は, yK1Trueであるような変数列の数f(S1,S2,,SK1)に一致し, (3)f(S1,S2,,SK)=f(S1,S2,,SK1) となります*3.
  • SKORであるとすると, xKyK1のどちらかがTrueであればよいです. すなわち, 以下の2パターンになります.
    • yK1Trueであるような変数列(x0,x1,x2,,xK1)xK=Falseを付け加えたもの
    • xK=Trueであるような任意の変数列(x0,x1,x2,,xK)
    したがって, (4)f(S1,S2,,SK)=f(S1,S2,,SK1)+2K となります.

このようにすれば, O(N)で求めることができます.

# dpdp!
def dpfunc(n,s):
dp = [0]*n
# N=1のときの初期値
if s[0] == "AND":
dp[0] = 1
else:
dp[0] = 3
# 1つ前の値を用いて計算していく
for i in range(1,n):
if s[i] == "AND":
dp[i] = dp[i-1]
else:
dp[i] = dp[i-1] + 2**(i+1)
return dp[-1]
# 入力
n = int(input())
s = [input() for _ in range(n)]
# 答えを出力
print(dpfunc(n,s))

E以降

E以降は私の能力不足故に省略いたします.

参考にしたサイト等

脚注

*1 : O(N3)と私は推測します. 間違っていたらコメントください.

*2 : O(N2)と私は推測します. 間違っていたらコメントください.

*3 : この場合, yK1Trueであるような変数列(x0,x1,x2,,xK1)xK=Trueを付け加えたものが, yKTrueであるような変数列になります.

Search

About Me

自分の写真
理系大学生でした. Bloggerを利用して発信を行っています.

Labels

Blog Archives