Java 8: 1,8е8 2,4е8
Цей запис не порівнюється з кількома іншими, які вже були, але я хотів опублікувати свою відповідь, оскільки мені було цікаво працювати над цим.
Основні оптимізації мого підходу такі:
- Кожне парне число має найменший коефіцієнт 2, тому їх можна додавати безкоштовно після опрацювання кожного непарного числа. В основному, якщо ви виконали роботу, щоб обчислити
T(N)
коли N % 2 == 1
, ви це знаєте T(N + 1) == T(N) + 2
. Це дозволяє мені почати рахувати з трьох і збільшити по ітерації на двійки.
- Я зберігаю свої прості номери в масиві на відміну від
Collection
типу. Це більше ніж удвічі збільшив N
я.
- Я використовую прості числа, щоб підрахувати число, а не виконувати сито Ератосфена. Це означає, що моє зберігання пам’яті майже повністю обмежене моїм масивом прайметів.
- Я зберігаю квадратний корінь числа, для якого я намагаюся знайти найменший множник. Я намагався @ user1354678 підходити кожен раз, коли потрібно простежувати основний фактор, але це коштувало мене приблизно в 1е7 від моєї оцінки.
Ось про все, що там є. Мій код повторюється від 3 до двох, поки він не виявить, що він потрапив або перевищив обмеження часу, і в цей момент він виписує відповідь.
package sum_of_smallest_factors;
public final class SumOfSmallestFactors {
private static class Result {
private final int number;
int getNumber() {
return number;
}
private final long sum;
long getSum() {
return sum;
}
Result(int number, long sum) {
this.number = number;
this.sum = sum;
}
}
private static final long TIME_LIMIT = 60_000_000_000L; // 60 seconds x 1e9 nanoseconds / second
public static void main(String[] args) {
SumOfSmallestFactors main = new SumOfSmallestFactors();
Result result = main.run();
int number = result.getNumber();
long sum = result.getSum();
System.out.format("T(%,d) = %,d\n", number, sum);
}
private int[] primes = new int[16_777_216];
private int primeCount = 0;
private long startTime;
private SumOfSmallestFactors() {}
private Result run() {
startClock();
int number;
long sumOfSmallestFactors = 2;
for (number = 3; mayContinue(); number += 2) {
int smallestFactor = getSmallestFactor(number);
if (smallestFactor == number) {
addPrime(number);
}
sumOfSmallestFactors += smallestFactor + 2;
}
--number;
Result result = new Result(number, sumOfSmallestFactors);
return result;
}
private void startClock() {
startTime = System.nanoTime();
}
private boolean mayContinue() {
long currentTime = System.nanoTime();
long elapsedTime = currentTime - startTime;
boolean result = (elapsedTime < TIME_LIMIT);
return result;
}
private int getSmallestFactor(int number) {
int smallestFactor = number;
int squareRoot = (int) Math.ceil(Math.sqrt(number));
int index;
int prime = 3;
for (index = 0; index < primeCount; ++index) {
prime = primes[index];
if (prime > squareRoot) {
break;
}
int remainder = number % prime;
if (remainder == 0) {
smallestFactor = prime;
break;
}
}
return smallestFactor;
}
private void addPrime(int prime) {
primes[primeCount] = prime;
++primeCount;
}
}
Працюючи в іншій системі (Windows 8.1, ядро Intel i7 @ 2,5 ГГц, 8 ГБ оперативної пам’яті) з останньою версією Java 8, помітно кращі результати без змін коду:
T(240,308,208) = 1,537,216,753,010,879