Euler : Problem 69

Posted by YpsilonTAKAI On 2011年12月7日水曜日 0 コメント

オイラーのトーシェント関数φ(n)の問題です。


まずは、普通に解いてみましがやっぱり15分もかかります。大きな数の素因数分解そのものに時間がかかるのが問題です。
答が出たので、まあこれでもいいかな...と思っていたのですが、帰りの電車で考えていたら、ひらめきまして、やり直しました。

※ 今回、OpenOfficeの数式エディタで数式を作ってみました。


nの素因数分解が







のようにあらわせるとき、φ(n)は、








で得られます。問題の答は、n/φ(n)を求めます。
最初のやりかたは、ここで、nを素因数分解して、この式をそのまま計算するものでした。

このあと、この式を眺めていて別の方法を思いつきました。

n/φ(n)の値はこういう値です。









nが消えるところがポイントです。
この式の値を大きくするということは、分母を小さくするということです。それには、掛け合わされているかっこの中を小さくすればすればよくて、かっこの中を小さくするには、pを小さくすればいいということがわかります。さらにその数が沢山あればなおいいですね。
ということで、求めるnは、小さな素因数を沢山持つものであることになります。
とはいっても、同じ素因数をいくら持っていても、pは増えませんので、これは、小さい素数から順に素因数として持つものということになります。

ようするに、2、3、5...と、小さいほうから順に1000000を超えないように素数を掛けていくと答が出るということです。
ただ、このやりかただと、重複している素因数がみつからないので、実際にもとめる数はこの数の倍数ということになります。


;; Problem 69 : 2011/12/6
;; This needs too long time.
;; "Elapsed time: 980693.545995 msecs"
(defn get-n-slash-phi-n [n]
(/ 1 (reduce * (map #(- 1 (/ 1 %)) (distinct (factors n))))))
(defn pe-69 [end-val]
(reduce #(if (> (first %1) (first %2)) %1 %2)
(pmap #(vector (get-n-slash-phi-n %) %) (range 2 (inc end-val)))))
;; Another implementation.
;; "Elapsed time: 0.225784 msecs"
(defn product-list
([col] (product-list (rest col) (first col)))
([col p]
(if (empty? col)
(list p)
(lazy-seq
(cons p
(product-list (next col) (* p (first col))))))))
(defn pe-69 [n]
(let [max-prime-product (last
(take-while #(< % n)
(product-list (get-prime-list))))]
(take-while #(< % n)
(map #(* max-prime-product %) (iterate inc 1)))))
;; 2013/1/11
;; finaly found that product-list do exactly same as (reductions *)
;; this is my final (really?) answer contains only 1 function.
;; "Elapsed time: 0.654412 msecs" includes prime sequence generation time.
(defn pe-69 [n]
(let [max-prime-product
(last
(take-while #(< % n)
(reductions * (create-primes (make-is-prime?)))))]
(last
(take-while #(< % n)
(map #(* max-prime-product %) (iterate inc 1))))))
view raw pe_69.clj hosted with ❤ by GitHub

前半はだめな実装。

- get-n-slash-phi-n
  n/φ(n) を計算する関数
  素因数分解をして、式のとおりに計算しています。

- pe-69
  2からnまでの数について、上の関数を使って、n/φ(n)が最大のものを求める。

下の二つができたやつ。
- product-list
  与えられたコレクションを順に掛けてできる数のリストを返す。
  2 2 2 2 2... なら 2 4 8 16 32... が返ります。

- pe-69
  説明の通りの動作をする関数。
  上の関数で素数を順に掛けた数のリストを作って、引数以下の最大数を求めます。さらに、
  それの倍数で引数以下のものをすべて求めます。


0 コメント:

コメントを投稿