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 | ``` |