Euler's Totient function, φ(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, φ(9)=6.
The number 1 is considered to be relatively prime to every positive number, so φ(1)=1.Interestingly, φ(87109)=79180, and it can be seen that 87109 is a permutation of 79180.
Find the value of n, 1 < n < 107, for which φ(n) is a permutation of n and the ratio n/φ(n) produces a minimum.
I think this problem is very simple at first. Calculating φ(n) and if it's a permutation of n, then calculate n/φ(n), and iterating this procedure through 1 to N=1e7. By recording the minimal n/φ(n) ratio and the corresponding n, we can get the result easily. But N=1e7 is very large, and requires many time to run. Here, I use a property of totient function, that is φ(mn)=φ(m)*φ(n) if m and n are relatively prime, and cache the φ(n) which was calculated previously.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #include<iostream> #include<cmath> #include<vector> #include<limits> using namespace std; const int N=1e7; bool isPerm(int x, int y); int totient(int n); int main() { double minRatio = std::numeric_limits<double>::max(); int res = 0; for (int n = 2; n < N; n++) { int p = totient(n); if (isPerm(n, p)) { double ratio = (double)n/p; if (ratio < minRatio) { minRatio = ratio; res = n; } } } cout << "Answers of PE 70: " << res << endl; return 0; } int totient(int n) { static int phis[N] = {0, 1, 1}; if (phis[n] != 0) { return(phis[n]); } for (int p=2; p <= sqrt(n); p++) { if ( n % p == 0 ) { int pk = p; while ( (n % (pk * p) == 0) ) { pk *= p; } if ( pk == n ) { // phis[n] = p^k phis[n] = n - n/p; return phis[n]; } if ( phis[pk] == 0 ) { phis[pk] = pk - pk/p; } phis[n] = totient(pk) * totient(n/pk); return phis[n]; } } phis[n] = n-1; return phis[n]; } bool isPerm(int x, int y) { vector<int> xv, yv; while ( x > 10 ) { xv.push_back(x % 10); x /= 10; } xv.push_back(x); while ( y > 10 ) { yv.push_back(y % 10); y /= 10; } yv.push_back(y); if (xv.size() != yv.size()) return false; sort(xv.begin(), xv.end()); sort(yv.begin(), yv.end()); for (int i=0; i<xv.size(); i++) { if (xv[i] != yv[i]) return false; } return true; } |
The idea of this code is brute-force. By caching the φ(n), the running time is acceptable, it took less than 2 mins to get the correct answer.
$ date(); ./pe70; date() Wed Dec 19 17:28:29 2012 Answers of PE 70: 8319823 Wed Dec 19 17:29:51 2012