Project Euler 200
色々飛ばして一気に200問目。
2, 5 の倍数以外は、耐素数性はないと仮定して解いた。
手順はこれ。
- q = 2 と固定して、条件を満たす sqube を小さいものから200個リストアップする。
- 次に q = 5 と固定して、リストアップ済みの sqube の最大値以下でかつ、条件を満たす sqube をリストアップする。
- 次に p = 2 or 5 と固定して、同様に条件を満たす sqube をリストアップする。
- これまでにリストアップした sqube をソートして、200番目の sqube を求める。(これまでにリストアップされたsqubeは243個だった)
この実行時間は 10秒 (Ruby 1.9.1 使用)
sqube 生成に使った素数は 10**6 以下の素数。(この数字は実験して最小のものを求めた)
ただ、この解法に辿り着くまでにはすごく時間がかかった。
というのも、「2, 5 の倍数以外は、耐素数性はない」という仮定をせずに愚直に解こうとしていたから、時間もメモリも使いまくって終わらないとか、工夫しようとするとやけにコードが難しくなり破綻したりしていた。
まあ、とりあえずなんとか解くことができてよかったよ。。
ちなみに、私は551人目の解答者のようです。Good!
- http://projecteuler.net/index.php?section=problems&id=200
- http://odz.sakura.ne.jp/projecteuler/index.php?Problem%20200
なお、今回の問題を解いているときに、今までに使っていた素数を求めるコードは実は遅いことに気づいた。(delete_ifを多用するのはまずい)
今までのコード
def primes_old(maxnum) return [2] if maxnum == 2 prime = 3.step(maxnum, 2).to_a (3..(Math.sqrt(maxnum).to_i)).each do |f| prime.delete_if {|t| t!=f && t%f == 0} end [2] + prime end
修正したコード
def primes(maxnum) ary = (2..maxnum).to_a (2..(Math.sqrt(maxnum).to_i)).each do |num| (num*2).step(maxnum, num).each do |t| ary[t-2] = nil end end ary.delete_if {|t| t.nil?} ary end
時間差は、10**6の引数で、それぞれ 20s, 6s
<補足>
2, 5 の倍数以外は、耐素数性はないと仮定したと書いたが、記事を書いた後にProblem 200のポストをちょいちょい見ていたら、実は2,5の倍数以外でも、"200"を含んで耐素数性を持つものが存在するらしいことが分かった。
105200812888979987 = 2011^2 * 2963^3
というか、みんなすごいですね。。