Project Euler 135, 45秒くらい。

どもです。


consecutive terms of an arithmetic progression というのを見逃して,
これはあれか? ペル方程式に持ち込むやつか? とか悩んでいて
にっちもさっちもいかんくて,問題文を良く読んだら,等差数列だったというオチ。
解けたことには解けたが,メモリを潤沢に使っている。

CL-USER> (time (euler-problem-135 (expt 10 6)))
(EULER-PROBLEM-135 (EXPT 10 6)) took 44,969 milliseconds (44.969 seconds) to run 
                    with 4 available CPU cores.
During that period, 44,782 milliseconds (44.782 seconds) were spent in user mode
                    93 milliseconds (0.093 seconds) were spent in system mode
750 milliseconds (0.750 seconds) was spent in GC.
 327,750,200 bytes of memory allocated.


find-e135-triplet とかいっているけど,返すのは,
(公差,x) のリスト。
あと,重複する場合があることに気づかず,少しハマッタ。
とりあえず的な感じで,remove-duplicates っといた。

(defun two-factors (n)
  (loop for i from 1 to (sqrt n)
        when (zerop (mod n i))
          collect (list i (/ n i))))

;; (two-factors 1155)
;; => ((1 1155) (3 385) (5 231) (7 165) (11 105) (15 77) (21 55) (33 35))

(defun find-e135-triplet (n)
  (remove-duplicates
   (mapcan (lambda (l)
             (let ((d (/ (+ (car l) (cadr l)) 4))
                   (x (car l)))
               ;;(format t "d=~A~%" d)
               (when (integerp d)
                 (if (<= x d)
                     (list (list d (cadr l)))
                     (append (list (list x (cadr l))
                                   (list (- (* 4 d) x) x)))))))
           (two-factors n))
   :test #'equal))

;; (find-e135-triplet 1155)
;; => ((289 1155) (97 385) (59 231) (43 165) (29 105) (23 77) (21 55) (55 21) (33 35) (35 33))

(defun euler-problem-135 (upper-bound)
  (loop for i from 1 below upper-bound
        for l = (find-e135-triplet i)
        count (= 10 (length l))))

あとは,毎度おなじみのグルグルグーグルとフォーラムでお勉強して,
改良だ。