1
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?

AtCoder ABC381 振り返り (Python A~D)

Last updated at Posted at 2024-11-23

abc381のA,B,C,DをPythonで。
本番ではA~Cの3完でした(Cは2TEL,1WA)。Dはコンテスト中の考察をコンテスト後にACしたコードです。

A問題

問題概要

条件を満たす文字列を11/22文字列を呼ぶ。与えられた文字列か11/22文字列か判定せよ。

解答

条件をすべてやる。添え字の扱いに注意

n = int(input())
s = input()

ans = "Yes"

if n % 2 == 0:
    ans = "No"
elif s[0 : (n + 1) // 2 - 1] != "1" * ((n + 1) // 2 - 1):
    ans = "No"
elif s[(n + 1) // 2 - 1] != "/":
    ans = "No"
elif s[(n + 1) // 2 :] != "2" * ((n) // 2):
    ans = "No"


print(ans)

B問題

問題概要

条件を満たす文字列を112文字列と呼ぶ。与えられた文字列が1122文字列か判定せよ。

解答

答えをYesにしておく。奇数だったらNo。前から2文字ずつ見る。setで出現した文字を記録して、二つの文字が一致しないか、出現済みの文字が出たらNoにする。

s = input()

ans = "Yes"
if len(s) % 2 != 0:
    ans = "No"
else:
    # 2, 3の条件を満たすかチェック
    # 隣り合う文字列が同じならok
    exist_char = set()
    for i in range(0, len(s), 2):
        if s[i] != s[i + 1]:
            ans = "No"
            break
        if s[i] in exist_char:
            ans = "No"
            break
        exist_char.add(s[i])

print(ans)

C問題

問題概要

与えられた文字列の中で、11/22文字列となる連続な部分文字列の最大値を求める。

コンテスト中の解答

前から連続する1を数える。/が出現したら、フラッグを立てて、直後の連続する2を数える。
答えは(1の連続数と2の連続数の小さい方)*2+1の最大値

# /の位置を求める
# /の左右を見ていき、左右の数字の塊がなくなったら、(塊の小さい方) * 2 + 1を答えに
n = int(input())
s = input()

ans = 1
is_right = False
left = 0  # 連続する1のみ数える
right = 0  # 連続する2のみ数える
for i in range(n):
    if not is_right:
        if s[i] == "1":
            left += 1
        elif s[i] == "2":
            left = 0
    elif is_right:
        if s[i] == "2":
            right += 1
        elif s[i] != "2":
            right = 0
            left = 0
            if s[i] == "1":
                left += 1
            is_right = False
    if s[i] == "/":
        is_right = True
    # print(f"{i=}, {left=}, {right=}, {ans=}")
    ans = max(ans, (min(left, right) * 2) + 1)
print(ans)

コンテスト後の解答

/が来たら左右の文字が条件を満たすか数えてもできる。

# 全探索していき、/か来たら、左右の文字を調べる
n = int(input())
s = input()

ans = 0
for i in range(n):
    if s[i] == "/":
        d = 0
        while True:
            left = i - d - 1
            right = i + d + 1
            if left < 0 or right >= n:
                break
            if s[left] != "1" or s[right] != "2":
                break
            d += 1
        ans = max(ans, d * 2 + 1)

print(ans)

(参考)TELした解答

11/22文字列の判定をスライスを使って求めようとした。
インデックス指定はO(1)に対して、スライスはO(スライスの長さ)と時間がかかる。

# /の位置を求める
# /の左右を見ていき、左右の数字の塊がなくなったら、(塊の小さい方) * 2 + 1を答えに
n = int(input())
s = input()

ans = 1
indices = [i for i in range(n) if s[i] == "/"]
count = 1
# 得られたindicesを使って、/の左右を見ていく
for i in indices:
    while True:
        # print(s[i - count : i], s[i + 1 : i + count + 1])
        if i - count < 0 or i + count >= n:
            break
        if (
            s[i - count : i] == "1" * count
            and s[i + 1 : i + count + 1] == "2" * count
        ):
            count += 1
        else:
            break
    count -= 1
    ans = max(ans, count * 2 + 1)

print(ans)

D問題

問題概要

条件を満たした数列を1122数列と呼ぶ。与えられた数列の連続する部分列で、1122数列となる最長のものの長さを求めよ。

コンテスト中の考察

  • 2つ飛ばしの尺取り法で出来そう
  • 偶数番目スタートの場合は判定できるが、奇数番目スタートの場合が判定できない
  • 一般化できず終了

コンテスト後の解答

無理に一般化せず偶奇分けて尺取り法をする。
場合によっては、leftがrightを越してしまうため、対策する。

# 2個飛ばしの尺取り法
# 偶奇で分ける
# 現れる数はsetで管理
n = int(input())
a = list(map(int, input().split()))

ans = 0
for left in range(2):
    right = left
    exit_num = set()
    for left in range(left, n, 2):
        while right + 1 < n:
            if a[right] != a[right + 1] or a[right] in exit_num:
                break
            exit_num.add(a[right])
            right += 2
        ans = max(ans, right - left)
        if left == right:
            right += 2
        exit_num.discard(a[left])

print(ans)

追記

D問題の公式解説にある解法2がよくわからなかった。分かる人がいたら教えてください。

感想

最近負けてばっかなのが悔しい。今回のC問題はスライスの計算量を考えずの実装のせいでTLEをしてしまったことが反省点。D問題は何となくわかりそうなところまで行くが、その後の詰めが甘いので、精進する必要がある。次回はレートがプラスになるよう頑張りたい。

1
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
1
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?