Project Euler Problem 12
これはかなりの良門ではないでしょうか。
約数の数が500以上になる最初の三角数を求めよ
三角数とは以下の式で書けるものです。
Nの素因数分解が下のようになる時
約数の個数は
となります。また、互いに素な2数は指数が重複しないですから、
nが奇数なら
で偶数なら
*1 = F(n/2)F(n+1)" src=http://www.texify.com/img/%5CLARGE%5C%21F%28T%28n%29%29%20%3D%20F%28n/2%29F%28n%2B1%29.gif align=center border=0>
です。従って、三角数の事はもう忘れて良くて、「自然数nのF(n)を求める方法」を考えれば良いです。
「よしじゃぁ、まず素数のテーブルを作って・・・」というのではダサいです。もっと調べて行きましょう。
まず、上で述べた事よりFは以下の漸化式を満たします。
こういった素因数分解に基づく漸化式は、エラトステネスのふるいをちょっと変形させれば解けます。
従って後は、m_nを求める方法を考えれば良いです。整数nの素因数に素数pが何個含まれるかをG(n,p)と表すと、
という漸化式になりますから、小さいnから順番に求める事ができます。
以上をまとめると以下のコードになります。
N = 20000 sieve = Array.new(N+1, 1) exp = Array.new(N+1) 2.upto(N) do |n| if sieve[n] == 1 then exp.fill(0) n.step(N, n) do |k| exp[k] = exp[k/n] + 1 sieve[k] *= (exp[k] + 1) end end r = (n % 2 == 0) ? sieve[n/2]*sieve[n-1] : sieve[n]*sieve[(n-1)/2] if r >= 500 then puts n*(n-1)/2 exit end end
実行時間は0.16秒くらいでした。
*1:n+1)/2)" src=http://www.texify.com/img/%5CLARGE%5C%21F%28T%28n%29%29%20%3D%20F%28n%29F%28%28n%2B1%29/2%29.gif align=center border=0> で偶数なら