私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「素因数分解で和が同じ」(CodeIQ)を参照してください。
整数を素因数分解し、分解した素数の和を求めることを考えます。
例えば、36を素因数分解すると2×2×3×3となり、分解した素数の和は 2+2+3+3=10 となります。
また、32を素因数分解すると2×2×2×2×2となり、分解した素数の和は 2+2+2+2+2=10 となります。
このように、分解した素数の和が同じになることがあります。
そこで、分解した素数の和 n が与えられたとき、元の整数がいくつあるかを求めます。
例えば、n = 10 のとき、上記の32, 36以外に21, 25, 30がありますので、全部で5つあります。
標準入力から n が与えられたとき、元の整数がいくつあるかを求め、標準出力に出力してください。
ただし、2≦n≦250とします。
【入出力サンプル】
標準入力
10
標準出力
5
Rubyで解答しています。
#!/usr/bin/ruby require 'prime' $Memo = {} def a008472(n) arr = Prime.prime_division(n) ret = 0 for a in arr ret += a[0] end return ret end def a000607(n) return 1 if n==0 return $Memo[n] if $Memo[n] != nil ret = 0 for k in 1..n ret += a008472(k)*a000607(n-k) end $Memo[n] = ret/n return ret/n end # main while line = gets line.strip! next if line.empty? p a000607(line.to_i) end
最初、メモ化再帰あたりで簡単にできそうと思いましたができず、OEIS頼りになりました。
#!/usr/bin/ruby require 'prime' def count(primes, n, st) return 0 if st >= primes.size return 1 if n == 0 return 0 if n < primes[st] ret = 0 for i in st...primes.size ret += count(primes, n-primes[i] , i) end return ret end def solve(n) primes = Prime.each(n).to_a ret = count(primes, n, 0) return ret end # main while line = gets line.strip! next if line.empty? p solve(line.to_i) endこのコードは総当たりで答えを求めます。
入力値を数値にしてsolve()に渡し、結果を印字します。
答えはk=1..nでA008472(k)*A000607(n-k)を足し合わせたものということです。
再帰呼び出しになっていて何回も同じnについて計算するのでメモ化しています。
OEISを見ればそれまでですが、nを素因数分解した時に現れる素数について重複をのぞいて足し合わせた値を求めます。
例えば、
n=2 => [2] => 2
n=4 => [22] => 2
n=6 => [2,3] => 2+3=5
n=8 => [23] => 2
n=9 => [32] => 3
n=12 => [22,3] => 2+3=5
という感じです。
最初に考えた単純な再帰の方法を拡張してうまくメモ化する方法はあるのでしょうか。
時々OEIS頼りで問題を解いていますが、私には数学が足りないのでOEISに書いてあることがわからない部分もかなりあります。また、サンプルコードも提示されているのですがMathematicaだったりMapleだったりが大半でこれも読めないのでOEISで見つけたら即回答できるというわけにも行きません。