プロジェクト

全般

プロフィール

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