Official
D - Yet Another Recursive Function Editorial
by
D - Yet Another Recursive Function Editorial
by
nok0
この問題は メモ化再帰 と呼ばれるテクニックの練習問題です。
まず、愚直に再帰をする解法の計算量を考えてみましょう。
\(f(0)\) が呼ばれる回数を考えると、これは \(2\) で割ることと \(3\) で割ることを繰り返して \(0\) に到達する方法の総数と一致します。小さく見積もっても、\(\binom{2\log_3 N}{\log_3 N}\) 程度はあり、\(N=10^{18}\) のとき明らかに間に合いません。
次に、メモ化再帰を行う場合の計算量を考えてみましょう。
\(f\) の引数として取りうる値の種類数を考えます。引数として取りうる値は、非負整数 \(x,y\) を用いて、\(\displaystyle\Big \lfloor \frac{N}{2^x3^y}\Big\rfloor\) という形で表されるものに限ることがわかります。
雑に見積もっても、\(x+y\) は \(\log_2{N}\) 以下の値しか取らないので、引数の種類数は \(\mathrm{O}(\log^ 2N)\) です。以上より、メモ化再帰を用いることでこの問題を \(\mathrm{O}(\log ^2N)\) で解くことができました。
実装例(python):
from functools import lru_cache
@lru_cache
def f(n):
if n == 0:
return 1
return f(n // 2) + f(n // 3)
print(f(int(input())))
posted:
last update: