0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Atcoder解法検討】ABC129 A~D Python

Last updated at Posted at 2024-09-11

A - Airplane

問題ページ : A - Airplane

考察

A問題は標準入出力と簡単な変数の処理ができれば十分なのですが、処理の部分が少しだけ考えさせられますね。
題意からはP,Q,Rのうち小さいほうから二つの数値の和が求められますが、これを$(P,Q,Rの合計値)-(P,Q,Rの最大値)$として処理しました。

コード

PQR = list(map(int, input().split()))
print(sum(PQR) - max(PQR))

B - Balance

問題ページ : B - Balance

考察

 この問題は累積和を使用して効率的に解く方法もありますが、B問題ということもあり題意どおりの愚直な全探索でも十分解くことができます。
愚直な全探索で解けるなら、その方がミスを減らしやすいので好みです。

コード

N = int(input())
W = list(map(int,input().split()))

ans = float("inf")
for T in range(N-1):
    S1 = 0
    S2 = 0
    for i in range(N):
        if i <= T:
            S1 += W[i]
        else:
            S2 += W[i]

    ans = min(ans,abs(S1-S2))

print(ans)

C - Typical Stairs

問題ページ : C - Typical Stairs

考察

DPの比較的簡単な典型。
DPテーブル(状態)は
$$dp[i] = i段目への移動方法数$$
遷移は
$$dp[i] = dp[i-1] + dp[i-2]$$
という貰う形式の方がイメージしやすいですが、コード中はいわゆる配る形式で記述しました。

\begin{array}{l}
dp[i+1] = dp[i+1] + dp[i] \\
dp[i+2] = dp[i+2] + dp[i] \\
\end{array}

床が壊れている段の扱いは、床の壊れている段からは進まないという風に読み替えて処理しています。
ある段が壊れている段に含まれるか否かの探索は壊れている段をset()に登録しておいた方が高速に処理できます。

コード

mod = 10 ** 9 + 7

N, M = map(int, input().split())
A = set()                           # 含まれているかの探索高速化のためsetで受ける
for _ in range(M):
    A.add(int(input()))

# dp[i] : i段目への移動方法
dp = [0] * (N + 2)
dp[0] = 1

# 遷移
for i in range(N):
    if i in A:continue     # 床が壊れている段からは移動しない
    dp[i + 1] = (dp[i + 1] + dp[i]) % mod
    dp[i + 2] = (dp[i + 2] + dp[i]) % mod

print(dp[N])

D - Lamp

問題ページ : D - Lamp

考察

二分法典型。
各行、各列毎に障害物の位置を列記したリストを作成。この時マップ外枠も障害物として位置-1,H or Wとしてリストに記載しておくと処理が楽になります。
あとは全マス探索で障害物でないマスなら、行内、列内で双方向にもっとも近い障害物位置を2分法で検出し照らされるマスの数を計算します。
計算量$O(HW\dot \log(max(H,W))$で処理できます。
二分法はbisectをインポートすれば簡単に使用できます。

コード

from bisect import bisect_left

H, W = map(int, input().split())
S = [ input() for _ in range(H)]

gyo = [[-1,W] for _ in range(H)]        # i行目にある障害物の位置   
retsu =[ [-1,H] for _ in range(W)]      # i列目にある障害物の位置

for i in range(H):
    for j in range(W):
        if S[i][j] == "#":
            gyo[i].append(j)
            retsu[j].append(i)

# 二分法にかけるためソート
for i in range(H):
    gyo[i].sort()
for i in range(W):
    retsu[i].sort()

# 全マスク探索
ans = 0
for i in range(H):
    for j in range(W):
        if S[i][j] != "#":
            pos1 = bisect_left(gyo[i],j)
            pos2 = bisect_left(retsu[j],i)

            len1 = gyo[i][pos1] - gyo[i][pos1 - 1] -1 
            len2 = retsu[j][pos2] - retsu[j][pos2-1] -1

            ans = max(ans, len1 + len2 -1)

print(ans)

E - Sum Equals Xor

問題ページ : E - Sum Equals Xor

考察

 この問題を見たときにまずDPにて解くことが思いつきました。下位から$k \ bit$までの組数を求めることができれば、下位から$k+1 \ bit$までの組数を求めることができる、という点からでしょうか。
 DPで解くとしたとき、DPテーブル(状態)の明確化と状態遷移の数式化が必要になります。まずDPテーブルは求めたい解でもありますので以下のように設定します。
$$dpL[i] : 下位からi\ bit$目まででa+b=a\ XOR\ b かつ a+b \leq Lを満たす(a,b)の組数$$
次に遷移を考慮すると
$$dpU[i] : 下位からi\ bit目まででa+b=a\ XOR\ b かつ a+b > Lを満たす(a,b)の組数$$
も必要になります。$a$の$i+1 \ bit$目と$b$の$i+1 \ bit$目との和が$L$の$i+1 \ bit$目より大きい場合には、$dpU[i]$からの遷移も必要となるからです。
 次に$a + b = a \ XOR \ b$との条件から、$a,b$の各$i \ bit$目は$(a[i],b[i]) = (0,0),(0,1),(1,0)$のいずれかの組み合わせになります。
 これらを元に$dpL[i],dpU[i]$から$dpL[i+1],dpU[i+1]$への遷移を考えます。これは$L[i+1]$が$0$か$1$かによって場合分けされます。

L[i+1] = 0の場合

dpL[i+1]への遷移

$dpL[i]$からの遷移は$(a[i+1],\ b[i+1]) = (0,0)$の1個
$dpU[i]$からの遷移は存在しない

dpU[i+1]への遷移

$dpL[i]$からの遷移は、$(a[i+1],\ b[i+1]) = (0,1),(1,0)$の2個
$dpU[i]$からの遷移は、$(a[i+1],\ b[i+1]) = (0,0),(0,1),(1,0)$の3個
数式化すると

\begin{array}{l}
dpL[i+1] = dpL[i] \\
dpU[i+1] = dpL[i] \times 2\ + \ dpU[i] \times 3 \\
\end{array}

L[i+1] = 1の場合

dpL[i+1]への遷移

$dpL[i]$からの遷移は、$(a[i+1],\ b[i+1]) = (0,0),(0,1),(1,0)$の3個
$dpU[i]$からの遷移は、$(a[i+1],\ b[i+1]) = (0,1),(1,0)$の2個

dpU[i+1]への遷移

$dpL[i]$からの遷移は存在しない
$dpU[i]$からの遷移は、$(a[i+1],\ b[i+1]) = (0,1),(1,0)$の2個
数式化すると

\begin{array}{l}
dpL[i+1] = dpL[i] \\
dpU[i+1] = dpL[i] \times 2\ + \ dpU[i] \times 3 \\
\end{array}

以上を実施すると$dpL[Lのbit長]$が解となります。

コード

mod = 10 ** 9 + 7

L = list(input())
L.reverse()
N = len(L)

# dpL[i] : i-bit目まで a + b = a xor b かつ a + b <= L
# dpU[i] : i-bit目まで a + b = a xor b かつ a + b > L
dpL = [0] * (N + 1)
dpU = [0] * (N + 1)
dpL[0] = 1

for i in range(N):
    if L[i] == "0":
        dpL[i + 1] = dpL[i]                           # dpLからの遷移 (a,b)=(0,0)   dpUからの遷移 なし
        dpU[i + 1] = (dpL[i] * 2 + dpU[i] * 3) % mod  # dpLからの遷移 (a,b)=(0,1),(1,0) dpUからの遷移 (a,b) = (0,0),(0,1),(1,0)
    elif L[i] == "1":
        dpL[i + 1] = (dpL[i] * 3 + dpU[i]) % mod      # dpLからの遷移 (a,b)=(0,0),(0,1),(1,0)   dpUからの遷移 (a,b) = (0,0)
        dpU[i + 1] = dpU[i] * 2                       # dpLからの遷移 なし  dpUからの遷移 (a,b) = (0,1),(1,0)

print(dpL[N])

'''
# debug確認
for i in range(num+1):
    print(dpL[i],dpU[i])
'''

F - Takahashi's Basics in Education and Learning

問題ページ : F - Takahashi's Basics in Education and Learning

青色diff以上は後日挑戦

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?