Java 8: 1.8e8 2.4e8
Bu giriş, şimdiye kadar olan diğer birkaç ile karşılaştırılamıyor, ancak bu konuda eğlendiğim için cevabımı göndermek istedim.
Yaklaşımımın ana optimizasyonları aşağıdaki gibidir:
- Her çift sayı en küçük 2 faktörüne sahiptir, bu nedenle her tek sayı işlendikten sonra bunlar ücretsiz olarak eklenebilir. Temel olarak,
T(N)
ne zaman hesaplamak için iş yaptıysanız N % 2 == 1
, bunu bilirsiniz T(N + 1) == T(N) + 2
. Bu sayıma üçte başlamama ve yineleme ile iki kat artmamı sağlıyor.
- Asal sayılarmı bir dizinin aksine bir dizide saklıyorum
Collection
. Bu iki katından fazla N
ulaşabilirim.
- Asal sayıları, Eratosthenes Elekleri yerine bir sayıyı çarpanlarına ayırmak için kullanıyorum. Bu, bellek depolamamın neredeyse tamamen primer dizimle sınırlı olduğu anlamına geliyor.
- En küçük faktörü bulmaya çalıştığım sayının kare kökünü saklıyorum. @ User1354678'in her seferinde asal bir faktörün karesini alma yaklaşımını denedim, ancak bu puanımdan yaklaşık 1e7'ye mal oldu.
Tüm bunların hepsi bu. Kodum, zaman sınırını vurduğunu veya aştığını algılayana kadar 3'ten iki kez tekrarlar, bu noktada cevabı tükürür.
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;
}
}
Java 8'in en son sürümüyle farklı bir sistemde (Windows 8.1, Intel core i7 @ 2.5 GHz, 8 GB RAM) çalışan, kod değişikliği yapılmadan belirgin şekilde daha iyi sonuçlar elde edildi:
T(240,308,208) = 1,537,216,753,010,879