Problem 69
Totient maximum
Euler’s Totient function, φ(n) [sometimes called the phi function], is used to determine the number of numbers less than 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.
n | Relatively Prime | φ(n) | n/φ(n) |
---|---|---|---|
2 | 1 | 1 | 2 |
3 | 1,2 | 2 | 1.5 |
4 | 1,3 | 2 | 2 |
5 | 1,2,3,4 | 4 | 1.25 |
6 | 1,5 | 2 | 3 |
7 | 1,2,3,4,5,6 | 6 | 1.1666… |
8 | 1,3,5,7 | 4 | 2 |
9 | 1,2,4,5,7,8 | 6 | 1.5 |
10 | 1,3,7,9 | 4 | 2.5 |
It can be seen that n=6 produces a maximum n/φ(n) for n ≤ 10.
Find the value of n ≤ 1,000,000 for which n/φ(n) is a maximum.
欧拉总计函数与最大值
在小于n的数中,与n互质的数的数目记为欧拉总计函数φ(n)(有时也称为φ函数)。例如,因为1、2、4、5、7和8均小于9且与9互质,故φ(9)=6。
n | 互质的数 | φ(n) | n/φ(n) |
---|---|---|---|
2 | 1 | 1 | 2 |
3 | 1,2 | 2 | 1.5 |
4 | 1,3 | 2 | 2 |
5 | 1,2,3,4 | 4 | 1.25 |
6 | 1,5 | 2 | 3 |
7 | 1,2,3,4,5,6 | 6 | 1.1666… |
8 | 1,3,5,7 | 4 | 2 |
9 | 1,2,4,5,7,8 | 6 | 1.5 |
10 | 1,3,7,9 | 4 | 2.5 |
可以看出,对于n ≤ 10,当n=6时n/φ(n)取得最大值。
当n ≤ 1,000,000时,求使得n/φ(n)取得最大值的n。
package projecteuler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
public class Prj69 extends TestCase {
public static final int UP_LIMIT = 1000000;
/**
* 欧拉函数phi(n)=n(1- 1/p1)(1-1/p2)...(1-1/pm);
*/
public void testTotientMaximum() {
double max = 2;
int maxId = 1;
IntegerDivisor div = new IntegerDivisor();
for (int i = 2; i <= UP_LIMIT; i++) {
div.clear();
div.divisor(i);
List<Long> primeList = div.primeList;
double val = 1;
for (int j = 0; j < primeList.size(); j++) {
int p = primeList.get(j).intValue();
val = val * p / (p - 1);
}
if (val > max) {
max = val;
maxId = i;
}
}
String fstr = "max=%s,n=%s";
fstr = String.format(fstr, Double.toString(max),
Integer.toString(maxId));
System.out.println(fstr);
}
public void testTotientMaximumUseProperty() {
int maxId = 1;
for (int i = 2;; i++) {
if (isPrime(i)) {
if( maxId * i > UP_LIMIT){
break;
}
maxId *= i;
}
}
System.out.println(maxId);
}
private boolean isPrime(int i) {
if (i <= 10) {
if (i == 2 || i == 3 || i == 5 || i == 7) {
return true;
}
return false;
}
if (i % 2 == 0) {
return false;
}
for (int j = 3; j * j <= i; j++) {
if (i % j == 0) {
return false;
}
}
return true;
}
public static class IntegerDivisor {
public Map<Long, Integer> primeMap = new HashMap<Long, Integer>();
public List<Long> primeList = new ArrayList<Long>();
public void clear() {
primeList.clear();
primeMap.clear();
}
public void divisor(long num) {
if (num <= 1)
return;
long prime = getPrime(
num,
primeList.size() == 0 ? 2
: primeList.get(primeList.size() - 1));
if (prime < 0) {
primeMap.put(num, 1);
primeList.add(num);
return;
} else {
primeList.add(prime);
int count = 0;
do {
count += 1;
num = num / prime;
} while (num % prime == 0);
primeMap.put(prime, count);
divisor(num);
}
}
private long getPrime(long num, long start) {
for (long i = start; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
return i;
}
}
return -1;
}
}
}