Problem 21 » 履歴 » バージョン 2
Noppi, 2024/01/04 05:38
1 | 1 | Noppi | [ホーム](https://redmine.noppi.jp) - [[Wiki|Project Euler]] |
---|---|---|---|
2 | # [[Problem 21]] |
||
3 | |||
4 | ## Amicable Numbers |
||
5 | Let $d(n)$ be defined as the sum of proper divisors of $n$ (numbers less than $n$ which divide evenly into $n$). |
||
6 | If $d(a) = b$ and $d(b) = a$, where $a \ne b$, then $a$ and $b$ are an amicable pair and each of $a$ and $b$ are called amicable numbers. |
||
7 | For example, the proper divisors of $220$ are $1, 2, 4, 5, 10, 11, 20, 22, 44, 55$ and $110$; therefore $d(220) = 284$. The proper divisors of $284$ are $1, 2, 4, 71$ and $142$; so $d(284) = 220$. |
||
8 | Evaluate the sum of all the amicable numbers under $10000$. |
||
9 | |||
10 | ## 友愛数 |
||
11 | d(n) を n の真の約数の和と定義する. (真の約数とは n 以外の約数のことである. ) |
||
12 | もし, d(a) = b かつ d(b) = a (a ≠ b のとき) を満たすとき, a と b は友愛数(親和数)であるという. |
||
13 | |||
14 | 例えば, 220 の約数は 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 なので d(220) = 284 である. |
||
15 | また, 284 の約数は 1, 2, 4, 71, 142 なので d(284) = 220 である. |
||
16 | |||
17 | それでは10000未満の友愛数の和を求めよ. |
||
18 | |||
19 | ```scheme |
||
20 | 2 | Noppi | (import (scheme base) |
21 | (gauche base) |
||
22 | (math prime) |
||
23 | (scheme list) |
||
24 | (scheme vector)) |
||
25 | |||
26 | (define (non-primes num) |
||
27 | (let ([primes-num (take-while (^n (<= n num)) (primes))] |
||
28 | [iota-4-num (iota (+ num 1 -4) 4)]) |
||
29 | (lset-difference = iota-4-num primes-num))) |
||
30 | |||
31 | (define (proper-divisors num) |
||
32 | (let loop ([n 2] [result '()]) |
||
33 | (cond |
||
34 | [(< num (* n n)) (delete-duplicates (cons 1 result))] |
||
35 | [(zero? (mod num n)) |
||
36 | (loop (+ n 1) (cons* n (div num n) result))] |
||
37 | [else (loop (+ n 1) result)]))) |
||
38 | |||
39 | (define (sum-divisors lis) |
||
40 | (map |
||
41 | (^n (cons n |
||
42 | (apply + (proper-divisors n)))) |
||
43 | lis)) |
||
44 | |||
45 | (define (amicable-numbers num) |
||
46 | (let ([divisors-list (sum-divisors (non-primes num))] |
||
47 | [table (make-vector (+ num 1) #f)]) |
||
48 | (for-each |
||
49 | (^[cell] |
||
50 | (let ([a (car cell)] |
||
51 | [b (cdr cell)]) |
||
52 | (when (and (not (= a b)) (<= b num)) |
||
53 | (set! (vector-ref table a) b)))) |
||
54 | divisors-list) |
||
55 | (vector-fold |
||
56 | (^[lis index num-or-f] |
||
57 | (cond |
||
58 | [(not num-or-f) lis] |
||
59 | [(not (vector-ref table num-or-f)) lis] |
||
60 | [(= index (vector-ref table num-or-f)) |
||
61 | (set! (vector-ref table index) #f) |
||
62 | (set! (vector-ref table num-or-f) #f) |
||
63 | (cons* index num-or-f lis)] |
||
64 | [else lis])) |
||
65 | '() |
||
66 | (list->vector (iota (+ num 1))) |
||
67 | table))) |
||
68 | |||
69 | (define answer-21 |
||
70 | (apply + (amicable-numbers 9999))) |
||
71 | |||
72 | (format #t "21: ~d~%" answer-21) |
||
73 | 1 | Noppi | ``` |