Project Euler Problem 034

http://projecteuler.net/index.php?section=problems&id=34
http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%2034

145は面白い数である. 1! + 4! + 5! = 1 + 24 + 120 = 145となる.

各桁の数の階乗の和が自分自身と一致するような数の総和を求めよ.

注: 1! = 1 と 2! = 2 は総和に含めてはならない.

Problem 30 と同じような問題なので、同じように解いた。

まず、どこまで調べたら良いのかを確認する。
7桁のときに 9! * 7 で 2540160 となり桁が追いつかなくなるので、最大値が分かる。


次に、問題の例で f(145) は f(14) + 5! 、つまり

f(n) = f(n/10) + (n % 10)!

となることが分かるのでキャッシュを使いながら計算していく。


計算範囲がProblem30よりも広いので、そのぶん時間がかかってしまう。もうちょっと良い方法ないかな。。

import itertools
import operator
import datetime


def euler034():
    def limit_value():
        x = reduce(operator.mul, range(1, 10))
        for i in itertools.count():
            n = 10 ** i
            m = x * (i + 1)
            if n > m:
                return x * i
    
    def make_facttable():
        d = [ 1 ]
        x = 1
        for i in xrange(1, 10):
            x *= i
            d.append(x)
        return d
    
    limit = limit_value()
    d = make_facttable()
    
    cache = [ 0 ] * limit
    cache[1] = 1
    cache[2] = 2
    
    result = 0
    for i in xrange(3, limit):
        x = cache[i/10] + d[i%10]
        
        if i == x:
            print '', i
            result += i
            
        cache[i] = x
        
    print result



begin = datetime.datetime.now()
euler034()
end = datetime.datetime.now()
print end - begin

答え: 40730 (145, 40585)
実行時間: 1.216319秒くらい