オイラーのトーシェント関数φ(n)の問題です。
まずは、普通に解いてみましがやっぱり15分もかかります。大きな数の素因数分解そのものに時間がかかるのが問題です。
答が出たので、まあこれでもいいかな...と思っていたのですが、帰りの電車で考えていたら、ひらめきまして、やり直しました。
※ 今回、OpenOfficeの数式エディタで数式を作ってみました。
nの素因数分解が
のようにあらわせるとき、φ(n)は、
で得られます。問題の答は、n/φ(n)を求めます。
最初のやりかたは、ここで、nを素因数分解して、この式をそのまま計算するものでした。
このあと、この式を眺めていて別の方法を思いつきました。
n/φ(n)の値はこういう値です。
nが消えるところがポイントです。
この式の値を大きくするということは、分母を小さくするということです。それには、掛け合わされているかっこの中を小さくすればすればよくて、かっこの中を小さくするには、pを小さくすればいいということがわかります。さらにその数が沢山あればなおいいですね。
ということで、求めるnは、小さな素因数を沢山持つものであることになります。
とはいっても、同じ素因数をいくら持っていても、pは増えませんので、これは、小さい素数から順に素因数として持つものということになります。
ようするに、2、3、5...と、小さいほうから順に1000000を超えないように素数を掛けていくと答が出るということです。
ただ、このやりかただと、重複している素因数がみつからないので、実際にもとめる数はこの数の倍数ということになります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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)))))) | |
前半はだめな実装。
- 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 コメント:
コメントを投稿