mean_abs_error’s blog

ソフトウェアとシステムの狭間

【AtCoder】PythonでABC326を解く

A問題: 2UP3DOWN

atcoder.jp

問題の概要

ビルの X階から Y階へ移動するとき、2階分までの上り、または、3階分までの下りであれば階段を使い、そうでないときはエレベータを使う。階段で移動するか判定せよ。

問題の考察

 Y - Xが範囲内に収まっているかで判定します。

コード

def main():
    x, y = map(int, input().split())
    ans = "Yes" if -3 <= (y - x) <= 2 else "No"
    print(ans)


if __name__ == "__main__":
    main()

B問題: 326-like Numbers

atcoder.jp

問題の概要

3桁の整数について、百の位のかずと十の位の数の積が一の位の数に等しいものを326-like numberと呼ぶ。整数 N以上の最小の326-like numberを求めよ。

問題の考察

制約を見ると分かるように326-like numberの最大値は919ですので、 [N, 919]の範囲で順に探索します。各位の数を取り出すには整数を文字列に変換すると楽です。

コード

def solve(N):
    for i in range(N, 920):
        a, b, c = map(int, list(str(i)))
        if a * b == c:
            return i

    return -1


def main():
    N = int(input())
    ans = solve(N)
    print(ans)


if __name__ == "__main__":
    main()

C問題: Peak

atcoder.jp

問題の概要

数直線上の座標 A_nにプレゼントが置かれている。ある座標 xを選ぶと半開区間 [x, x + M)にあるプレゼントを全て獲得できる。適切に xを選ぶと最大でいくつのプレゼントを獲得できるか。

問題の考察

配列 Aをソートした上で、 xを各 A_nで全探索しつつ高速に獲得できるプレゼント数をカウントします。二分探索で x+M未満の数と x未満の数をそれぞれ求めて差を計算すると、半開区間にあるプレゼント数を \mathcal O (\log N)でカウントできます。前処理としてのソート、および、全探索と二分探索により、 \mathcal O (N \log N)の計算量でプレゼント数の最大値を計算できました。

コード

from bisect import bisect_left


def solve(N, M, A):
    ans = 0
    for a in A:
        x = bisect_left(A, a + M) - bisect_left(A, a)
        ans = max(ans, x)

    return ans


def main():
    N, M = map(int, input().split())
    A = list(map(int, input().split()))
    A = sorted(A)
    ans = solve(N, M, A)
    print(ans)


if __name__ == "__main__":
    main()

E問題: Revenge of "The Salary of AtCoder Inc."

atcoder.jp

問題の概要

そのままですので、略します。

問題の考察

 f(x)をダイスで xが出ているときの給料の期待値とします。ダイスで xが出ているときにさらに手順を踏むと、次のダイス z 1から xまでのときはそれぞれ \frac{1}{N}の確率で A_xが支給され、 x+1から Nまでのときはそれぞれ \frac{1}{N}の確率で A_x + f(z)が支給されます。
 f(x) = \frac{1}{N} \sum_{z=1}^x A_x + \frac{1}{N} \sum_{z=x+1}^N [ A_x +  f(z) ] = A_x + \frac{1}{N} \sum_{z=x+1}^N  f(z)

上記の式について、 x=Nの状態から x=0の状態まで計算していけば、 x=0のときの給料の期待値が計算できます。なお、高速化のために式の最後の総和では累積和を用います。これによって、計算量 \mathcal O (N)で期待値が求まります。なお、答えを \bmodで計算する必要があるため、 Nでの割り算は \mathrm{pow} (N, -1, 998244353)の掛け算で実現します。

コード

def solve(N, A, MOD=998244353):
    A = [0] + A
    dp = [0] * (N + 1)
    ep = [0] * (N + 2)
    modinv_N = pow(N, -1, MOD)
    for x in range(N, -1, -1):
        dp[x] = A[x]
        dp[x] += ep[x + 1] * modinv_N % MOD
        dp[x] %= MOD
        ep[x] = dp[x] + ep[x + 1]
        ep[x] %= MOD

    ans = dp[0]

    return ans


def main():
    N = int(input())
    A = list(map(int, input().split()))
    ans = solve(N, A)
    print(ans)


if __name__ == "__main__":
    main()