【Python3】【ABC135】AtCoder Beginner Contest 135 参加記録 (D まで)

abc135

最近土日夜に予定があることが多く、なかなかコンテストに参加できておらず、昨日久々に参加したので記録を書いていきます。

3完しか出来なかったので伸び悩んでいます😭

ABC135 A – Harmony

相違なる整数 \(A, B\) があります。
\(|A−K| = |B−K|\) となるような整数 \(K\) を出力してください。
そのような整数が存在しなければ、代わりに "IMPOSSIBLE" を出力してください。

https://atcoder.jp/contests/abc135/tasks/abc135_a

\(|A – K| = |B – K|\) を変形すると、 \(A – K = B – K\) or \(A – K = K – B\) となり、 \(A = B\) or \(K = \frac{A + B}{2} \) といえます。

今回は、問題文に 相異なる整数 と書いてあるので、 \(K = \frac{A + B}{2}\) であり、これが整数かどうかで "IMPOSSIBLE" かどうかを判定すれば OK ですね。

回答案

Python3 で 22 ms で AC。

A, B = map(int, input().split())
if (A + B) % 2 == 0:
    print((A + B) // 2)
else:
    print("IMPOSSIBLE")

ABC135 B – 0 or 1 Swap

\(\{1, 2, …, N\}\) を並び替えた数列 \(p = \{p_1, p_2, …, p_N\}\) があります。
あなたは一度だけ、整数  \(i, j   (1 \leq i < j \leq N)\) を選んで \(p_i\) と \(p_j\) を入れ替える操作を行うことができます。操作を行わないことも可能です。
\(p\) を昇順にすることができるなら "YES" を、できないならば "NO" を出力してください。

https://atcoder.jp/contests/abc135/tasks/abc135_b

\(p\) の index と \(p\) の値を比較して、異なるものをカウントしたときの個数が 2 以下になるときに昇順に出来ます。

回答案

Python3 で 17 ms で AC。

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

cnt = 0
for i in range(N):
    if i + 1 == p[i]:
        cnt += 1

if cnt >= N - 2:
    print("YES")
else:
    print("NO")

ABC135 C – City Savers

\(N + 1\) 個の街があり、 \(i\) 番目の街は \(A_i\) 体のモンスターに襲われています。
\(N\) 人の勇者が居て、\(i\) 番目の勇者は \(i\) 番目または \(i + 1\) 番目の街を襲っているモンスターを合計で \(B_i\) 体まで倒すことができます。
\(N\) 人の勇者がうまく協力することで、合計して最大で何体のモンスターを倒せるでしょうか。

https://atcoder.jp/contests/abc135/tasks/abc135_c

A[0] から順番に見ていきましょう。 B[0]A[0] を上回っている場合、余剰分が A[1] だけに作用します。つまり、 A[2] 以降には作用しないことに注意する必要があります。

そこで、回答では余剰分 surplus を設定し毎回更新していくことにしています。無駄のないようにモンスターを倒していく必要があるので、 A[i] に先に作用するのは B[i] でなく surplus にする必要があります。

回答案

Python3 で 147 ms で AC。

N = int(input())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

ans, surplus = 0, 0
for i in range(N):
    tmp = min(A[i], surplus)
    ans += tmp
    A[i] -= tmp
    if B[i] > A[i]:
        ans += A[i]
        surplus = B[i] - A[i]
    else:
        ans += B[i]
        surplus = 0
tmp = min(A[N], surplus)
ans += tmp
print(ans)

ABC135 D – Digits Parade

文字列 \(S\) が与えられます。\(S\) の各文字は、数字 ("0" ~ "9") か "?" です。
"?" を数字に置き換えてできる整数のうち、\(13\) で割って \(5\) あまる数は何通りあるでしょうか?ただし、頭文字が \(0\) である場合も整数とみなすものとします。
答えは非常に大きくなる可能性があるため、\(10^9 + 7\) で割ったあまりを答えてください。

https://atcoder.jp/contests/abc135/tasks/abc135_d

\(S\) の長さが \(10^5\) なので、全探索しようとすると \(O(10^{10^5})\) となって出来ません。ということで他の方法を考えることになります。。。

剰余の計算を以下のように桁ごとに分割して考えることができることに着目すると、 DP で行けそう。

"??2??5" を 13 で割った余り
= "?"*10^5 + "?"*10^4 + 2*10^3 + "?"*10^2 + "?"*10 + 5 を 13 で割った余り
= ("?"*10^5 を 13 で割った余り) + ("?"*10^4 を 13 で割った余り) + (2*10^3 を 13 で割った余り) + ("?"*10^2 を 13 で割った余り) + ("?"*10 を 13 で割った余り) + (5 を 13 で割った余り)

すなわち次のように DP テーブルを設定することでうまくいくことが分かります。

  • dp[i][j]: $S$ の後ろから $i$ 桁を 13 で割ったあまりが $j$ となるようなものの個数
  • 求めるもの: dp[len(S)][S] ($S$ を 13 で割ったあまりが $5$ となるようなものの個数)

あとは状態間の遷移を考えてあげれば良いですね。参考までに "??2??5" の場合の遷移を表として書いておきます。

参考: ある数 X = “??2??5” を下から見ていったときの 13 で割った余りの遷移

X0123456789101112
01000000000000
50000010000000
?51011111101101
??58788788878878
2??58878887887887
?2??578767679767679767678777677
??2??5771768768772768768771769768770770768769

回答案

PyPy3 で 721 ms で AC。(Python3 では通せませんでした…)

INF = 10 ** 9 + 7

S = input()
# dp[i][j]はうしろからi桁を13で割った余りがjであるものの個数
dp = [[0] * 13 for _ in range(len(S) + 1)]
dp[0][0] = 1
mul = 1

for i in range(len(S)):
    x = S[-(i + 1)]
    if x == "?":
        for k in range(10):
            for j in range(13):
                dp[i + 1][(mul * k + j) % 13] += dp[i][j]
                dp[i + 1][(mul * k + j) % 13] %= INF
    else:
        k = int(x)
        for j in range(13):
            dp[i + 1][(mul * k + j) % 13] += dp[i][j]
            dp[i + 1][(mul * k + j) % 13] %= INF
    mul = mul * 10 % 13  # 計算量削減のためここで13で割っている

print(dp[len(S)][5])

この記事を書いた人

サトゥー

東大学際情報学府M1。情報科学と教養の海に溺れています。面白いことをやるのがすきです。