黒ココアさんのメモ置き場

メモを置いたり置かなかったり

ABC340 C - Divide and Divide

atcoder.jp

問題

  • 整数Nが1つだけ黒板に書かれてるよ
  • 2以上の整数が全てなくなるまで、以下の操作を繰り返すよ
    • 2以上の整数を1つ選んで、$x$とする
    • $x$を1つ消して、$\lfloor \frac{x}{2} \rfloor$と、$\lceil \frac{x}{2} \rceil$を
    • この操作で、お金が$x$円かかるよ
  • 最終的に操作が行えなくなるまでにかかる金額はいくら?

成約

  • $1 \leq N \leq 2 \times 10^{17}$

思考

  • もしNが0なら…0円。
  • もしNが1なら…0円。
  • もしNが2なら…2を選んで2円→1が2個できるので、2円+(0円+0円) = 2円
  • もしNが3なら…3を選んで3円→1と2が1個ずつできるので、3円+(0円+2円) = 5円
  • もしNが4なら…4を選んで4円→2が2個できるので、4円+(2円+2円) = 8円
  • 何か、再帰関数っぽい、見た目をしている。
  • 1が1つだけ書かれている時のコスト〜Xが1つだけ書かれている時のコストがわかっていたら、X+1が1つだけ書かれているときのコストはすぐ出てくる、けど…
  • $10^{17}$は、なぁ…流石にdpテーブル作るのは、重たい…
  • ので、頑張って、再帰関数を、書く
    • メモ化しようね
    • dict使っても良いけど、lru_cacheで一撃。便利。

コード

from functools import lru_cache

N = int(input())

@lru_cache(maxsize=None)
def f(x):
    if x == 0 or x == 1:
        return 0
    return x + f(x//2) + f((x+1)//2)

print(f(N))