Project EulerをSchemeで(26-30)
1ヶ月ほどご無沙汰してたけど、Kyoto.lispにも行ってきたことだし、もっとLisp勉強しよう。
今度参加するときはLT出来るようにネタを作っときたいな。
今回からGaucheのver.が0.9.2->0.9.3になりました。
iotaがコアに入って楽、という程度の使いこなしなんですがね…
(use srfi-1) (define (primes n) (if (<= n 2) '() (let1 u (truncate (sqrt n)) (let loop ((ps '(2)) (l (unfold (cut < n <>) values (cut + 2 <>) 3))) (let1 m (car l) (if (> m u) (append (reverse ps) l) (loop (cons m ps) (remove (^(x) (zero? (modulo x m))) l)))))))) (define (integer->list i) (letrec ((i->rl (^(i) (cons (modulo i 10) (if (< i 10) '() (i->rl (quotient i 10))))))) (reverse (i->rl i))))
問26.
d < 1000 なる 1/d の中で循環節が最も長くなるような d を求める問題
; 小数部の循環 <=> 余りの循環 なので同じ余りが出るまで計算すればよい ; また, p / q の余りは0 ~ q-1の範囲なので, 循環節の長さは最大でq ; よって大きいnから調べ, それまでの最大値よりもnが小さくなれば計算を終了できる (define (e26) (define (recurring-length n) (let1 v (make-vector n #f) (vector-set! v 1 0) (let loop ((p 1) (c 0)) (if (< p n) (loop (* p 10) (+ c 1)) (let1 r (remainder p n) (if (zero? r) 0 (if (vector-ref v r) (- c (vector-ref v r)) (begin (vector-set! v r c) (loop (* r 10) (+ c 1)))))))))) (let loop ((n 999) (ans '(0 0))) (if (< n (cadr ans)) (car ans) (loop (- n 1) (let1 len (recurring-length n) (if (< (cadr ans) len) (list n len) ans))))))
問27.
n^2 + an + b のnに連続した整数を与えて素数を生成するとき、その長さが最大となるようなa, bを求める問題
; f(n) = n^2 + an + b とすると ; f(0) = b, f(1) = a + b + 1 ; ∴ b: 素数, a + b + 1: 素数 と考えて良い ; また, b = 2 のときを考えると ; f(2) = 2^2 + 2a + 2 となり, ; これは明らかに2以上の偶数なので, bは3以上の素数と考えて良い ; またこのとき, aは奇数となる (define (e27) (let ((v (make-vector 1000000 #f)) (ps_1000 (primes 1000))) (for-each (cut vector-set! v <> #t) (primes 1000000)) ((^(ans) (* (car ans) (cadr ans))) (fold (^(val prev) (if (> (caddr val) (caddr prev)) val prev)) '(0 0 0) (append-map (^(a) (map (^(b) (list a b (length (take-while (^(n) (let1 y (+ (* n n) (* a n) b) (and (positive? y) (vector-ref v y)))) (iota b))))) ps_1000)) (iota 1000 -999 2))))))
問28.
ルールに従って作成した1001×1001の升目の、対角線上の数字の合計を求める問題
; 1周毎の四隅の合計を足し続ける (define (e28) (let loop ((sides 1) (pos 1) (ans 1) (d 2)) (if (= sides 1001) ans (loop (+ sides 2) (+ pos (* 4 d)) (+ ans (* 4 pos) (* 10 d)) (+ d 2)))))
問29.
a^bを 2<=a<=100, 2<=b<=100 で動かしたときに何種類の数字が生成されるか求める問題
; 力押し (define (e29) (length (delete-duplicates (append-map (^(a) (map (^(b) (expt a b)) (iota 99 2))) (iota 99 2)))))
問30.
各桁を5乗した数の和が元の数と一致するような数の総和を求める問題
; そのまんま (define (e30) (let1 max-e (* 5 (expt 9 5)) (apply + (filter-map (^(n) (and (= n (apply + (map (cut expt <> 5) (integer->list n)))) n)) (iota (- max-e 1) 2)))))