AtCoder Beginner Contest 121

400点とれなかったー。回答なしで時間切れ後にできるのは悔しい。

atcoder.jp

これは200点問題だろう、、。解説も要らん。

def solve(N, M, ABs):
    ABs = sorted(ABs)
    ans = 0
    for a, b in ABs:
        if b < M:
            ans += a * b
            M -= b
        else:
            ans += M * a
            break
    return ans


if __name__ == "__main__":
    N, M = tuple(map(int, input().split(" ")))
    ABs = [tuple(map(int, input().split(" "))) for __ in range(N)]
    print(solve(N, M, ABs))

atcoder.jp

そしてこっちは2時間かかって爆死。

Aから始まってBの間にはそれぞれのbitで周期性があることはすぐわかるので、この間の1の数を数える。

周期性というのは、例えば、3から10まで書き出したとき、一番下のビットは2つごとに同じビット列が並び、 次のビットは4つごと、さらに次は8つごととなってること。

0000000011
0000000100
0000000101
0000000110
0000000111
0000001000
0000001001
0000001010

どん詰まりしたのは、「Aから始まって、周期の始まり」、「周期中」、「周期の終わりからBまで」の3つをバラバラに求めてカウントしようとしたから。

はまりにはまって、コンテスト終了後に、AからBまでの1の数は「0からBまでの1の数」から「0~A-1までの1の数」を引けばよいことに気が付く。 これは、別のメソッドの切り出して実装。 もっと大局的に考えなきゃならん。

明らかに遅いとわかりつつ、今回はslow_solveの実装が楽だったのでさくっと書いてテストで実行。 これがあるとほぼ完ぺきなテストができるので安心。

countのメソッドに関してはテストそのものを間違えてしまった。0を周期にカウントしなかったために、一つずれていた。 修正は苦労しなかったが気が付くのに時間がかかった、、assertの量が苦労を物語る。

def slow_solve(A, B):
    ans = A
    for i in range(A + 1, B + 1):
        ans = ans ^ i
    return ans


def count(k, cycle):
    k += 1
    tans = (k // cycle) * (cycle // 2)
    res = k % cycle
    if res >= cycle // 2:
        tans += res % (cycle // 2)
    return tans


assert (count(8, 8) == 4)
assert (count(7, 8) == 4)
assert (count(6, 8) == 3)
assert (count(5, 8) == 2)
assert (count(4, 8) == 1)
assert (count(3, 8) == 0)
assert (count(2, 8) == 0)
assert (count(1, 8) == 0)
assert (count(0, 8) == 0)

assert (count(8, 4) == 4)
assert (count(7, 4) == 4)
assert (count(6, 4) == 3)
assert (count(5, 4) == 2)
assert (count(4, 4) == 2)
assert (count(3, 4) == 2)
assert (count(2, 4) == 1)
assert (count(1, 4) == 0)
assert (count(0, 4) == 0)

assert (count(8, 2) == 4)
assert (count(4, 2) == 2)
assert (count(3, 2) == 2)
assert (count(2, 2) == 1)
assert (count(1, 2) == 1)
assert (count(0, 2) == 0)


def solve(A, B):
    cycle = 2
    ans = ""
    for _ in range(40):
        acount = count(A - 1, cycle)
        bcount = count(B, cycle)
        ans = str((bcount - acount) % 2) + ans
        cycle *= 2
    return int(ans, base=2)


assert (slow_solve(2, 4) == solve(2, 4))
assert (slow_solve(2, 5) == solve(2, 5))
assert (slow_solve(2, 6) == solve(2, 6))
assert (slow_solve(2, 7) == solve(2, 7))

assert (solve(1, 1) == 1)
assert (solve(2, 4) == 5)
assert (solve(123, 456) == 435)

if __name__ == "__main__":
    A, B = tuple(map(int, input().split(" ")))
    print(solve(A, B))

もっとしっかり考えましょう。そして400問題で精進しよう。 来週はGrandコンテストでレート下降は避けられないので水色はしばらくお預けかな、、、