Problem 70 » 履歴 » バージョン 2
Noppi, 2024/02/01 04:59
1 | 1 | Noppi | [ホーム](https://redmine.noppi.jp) - [[Wiki|Project Euler]] |
---|---|---|---|
2 | # [[Problem 70]] |
||
3 | |||
4 | ## Totient Permutation |
||
5 | Euler's totient function, $\phi(n)$ [sometimes called the phi function], is used to determine the number of positive numbers less than or equal to $n$ which are relatively prime to $n$. For example, as $1, 2, 4, 5, 7$, and $8$, are all less than nine and relatively prime to nine, $\phi(9)=6$.<br>The number $1$ is considered to be relatively prime to every positive number, so $\phi(1)=1$. |
||
6 | |||
7 | Interestingly, $\phi(87109)=79180$, and it can be seen that $87109$ is a permutation of $79180$. |
||
8 | |||
9 | Find the value of $n$, $1 \lt n \lt 10^7$, for which $\phi(n)$ is a permutation of $n$ and the ratio $n/\phi(n)$ produces a minimum. |
||
10 | |||
11 | ## トーティエント関数の置換 |
||
12 | オイラーのトーティエント関数 φ(n) (ファイ関数とも呼ばれる) とは, n 未満の正の整数で n と互いに素なものの個数を表す. 例えば, 1, 2, 4, 5, 7, 8 は9未満で9と互いに素であるので, φ(9) = 6 となる. |
||
13 | 1 は全ての正の整数と互いに素であるとみなされる. よって φ(1) = 1 である. |
||
14 | |||
15 | 面白いことに, φ(87109)=79180 であり, 87109は79180を置換したものとなっている. |
||
16 | |||
17 | $1 \lt n \lt 10^7$ で φ(n) が n を置換したものになっているもののうち, n/φ(n) が最小となる n を求めよ. |
||
18 | |||
19 | ```scheme |
||
20 | 2 | Noppi | (import (scheme base) |
21 | (gauche base) |
||
22 | (scheme list)) |
||
23 | |||
24 | (define (prime-generator) |
||
25 | (let ([current 11] |
||
26 | [primes '(2 3 5 7)] |
||
27 | [inc 2] |
||
28 | [next-inc (^n (if (= n 2) 4 2))]) |
||
29 | (^[] |
||
30 | (let loop ([rest-primes primes]) |
||
31 | (if (null? rest-primes) |
||
32 | (begin0 |
||
33 | current |
||
34 | (set! primes (append primes `(,current))) |
||
35 | (set! current (+ current inc)) |
||
36 | (set! inc (next-inc inc))) |
||
37 | (let ([p (car rest-primes)]) |
||
38 | (cond |
||
39 | [(< current (* p p)) |
||
40 | (begin0 |
||
41 | current |
||
42 | (set! primes (append primes `(,current))) |
||
43 | (set! current (+ current inc)) |
||
44 | (set! inc (next-inc inc)))] |
||
45 | [(zero? (mod current p)) |
||
46 | (set! current (+ current inc)) |
||
47 | (set! inc (next-inc inc)) |
||
48 | (loop primes)] |
||
49 | [else |
||
50 | (loop (cdr rest-primes))]))))))) |
||
51 | |||
52 | (define my-primes |
||
53 | (generator->lseq 2 3 5 7 (prime-generator))) |
||
54 | |||
55 | (define (select-prime-list n1 n2) |
||
56 | (drop-while |
||
57 | (^n (< n n1)) |
||
58 | (take-while (^n (<= n n2)) |
||
59 | my-primes))) |
||
60 | |||
61 | (define (number->vector num) |
||
62 | (assume (exact-integer? num)) |
||
63 | (assume (not (negative? num))) |
||
64 | (let ([vec (make-vector 10 0)]) |
||
65 | (let loop ([rest num]) |
||
66 | (if (zero? rest) |
||
67 | vec |
||
68 | (let ([tail-num (mod rest 10)]) |
||
69 | (vector-set! vec tail-num |
||
70 | (+ (vector-ref vec tail-num) 1)) |
||
71 | (loop (div rest 10))))))) |
||
72 | |||
73 | (define (permutate? num1 num2) |
||
74 | (let ([vec1 (number->vector num1)] |
||
75 | [vec2 (number->vector num2)]) |
||
76 | (let loop ([index 0]) |
||
77 | (cond |
||
78 | [(< 9 index) #t] |
||
79 | [(not (= (vector-ref vec1 index) |
||
80 | (vector-ref vec2 index))) |
||
81 | #f] |
||
82 | [else |
||
83 | (loop (+ index 1))])))) |
||
84 | |||
85 | ;;; n の素因数が p1, p2, ... , pk の時 |
||
86 | ;;; φ(n) = n * (1 - 1/p1) * (1 - 1/p2) * ... * (1 - 1/pk) |
||
87 | ;;; φ(n)/n = (1 - 1/p1) * (1 - 1/p2) * ... * (1 - 1/pk) |
||
88 | ;;; = (p1 - 1)/p1 * (p2 - 1)/p2 * ... * (pk - 1)/pk |
||
89 | ;;; ∴ n/φ(n) = p1/(p1 - 1) * p2/(p2 - 1) * ... * pk/(pk - 1) |
||
90 | ;;; |
||
91 | ;;; この時の n/φ(n) を最小化することを考えると |
||
92 | ;;; 1. 各 p は大きい方が良い |
||
93 | ;;; 2. 各 p は少ない方が良い |
||
94 | ;;; 3. ただし、n が素数(pの数が1)の時は φ(n) = n - 1 なので |
||
95 | ;;; n と φ(n) が置換の数になることはありえない |
||
96 | ;;; 以上のことから、p1 * p2 <= 10^7 を満たす |
||
97 | ;;; なるべく大きな p1, p2 を求めれば良い |
||
98 | |||
99 | (define (totient p1 p2) |
||
100 | (* p1 p2 (- 1 (/ 1 p1)) (- 1 (/ 1 p2)))) |
||
101 | |||
102 | (define (select-numbers p1 p2 max-num) |
||
103 | (filter (^c (<= (* (car c) (cdr c)) max-num)) |
||
104 | (fold-right (^[n lis] |
||
105 | (append |
||
106 | (map (^m (cons n m)) |
||
107 | (select-prime-list (+ n 2) p2)) |
||
108 | lis)) |
||
109 | '() |
||
110 | (drop-right (select-prime-list p1 p2) 1)))) |
||
111 | |||
112 | ;;; 3162 が n^2 <= 10^7 を満たす最大の整数だったので |
||
113 | ;;; とりあえず 2003 ~ 3997 の範囲で求めてみる |
||
114 | (define (perm-list) |
||
115 | (filter (^c (permutate? (car c) (cdr c))) |
||
116 | (map (^c `(,(* (car c) (cdr c)) |
||
117 | . ,(totient (car c) (cdr c)))) |
||
118 | (select-numbers 2003 3997 #e1e7)))) |
||
119 | |||
120 | (define (answer) |
||
121 | (fold (^[lis knil] |
||
122 | (if (< (cdr lis) (cdr knil)) |
||
123 | lis |
||
124 | knil)) |
||
125 | `(0 . ,(greatest-fixnum)) |
||
126 | (map (^c `(,(car c) |
||
127 | . ,(/ (car c) (cdr c)))) |
||
128 | (perm-list)))) |
||
129 | |||
130 | (define answer-70 (car (answer))) |
||
131 | |||
132 | (format #t "70: ~d~%" answer-70) |
||
133 | 1 | Noppi | ``` |