Используйте базовую математическую структуру , это резко изменит время выполнения вашей программы.Кстати, это относится и к проблеме 10;если вы не можете сделать это за несколько миллисекунд, вы использовали крайне неэффективный алгоритм.На самом деле, я советую вам сначала поработать над проблемой 10, потому что проблема 12 основана на ней.
Ниже я приведу лучший алгоритм для задачи 12, но сначала приведу наблюдение, которое должно ускоритьваша программа значительно.Если два числа x и y взаимно просты (т.е. они не имеют общего делителя, кроме 1), то d (x · y) = d (x) · d (y).В частности, для числа треугольника d (n · (n + 1)) = d (n) · d (n + 1).Таким образом, вместо итерации по номерам треугольников n · (n + 1), итерации по n: это значительно уменьшит размер аргументов, передаваемых в d (n).
Если вы выполните эту оптимизацию, вы 'Заметим, что вы вычисляете d (n) дважды подряд (один раз как d ((n-1) +1) и один раз как d (n)).Это говорит о том, что кэширование результата d является хорошей идеей.Приведенный ниже алгоритм делает это, но также вычисляет d снизу вверх, а не сверху вниз, что более эффективно, потому что умножение намного быстрее, чем факторинг.
Задача 10 можетбыть решена с помощью простого применения сита Eratosthenes .Заполните массив логических значений (т. Е. Битовый вектор) размером 2000000 так, чтобы sieve[i]==true
, если i
было простым числом;затем суммируйте числа, для которых sieve[i]==true
.
Проблема 12 может быть решена путем обобщения сита Эратосфена.Вместо того, чтобы делать sieve[i]
логическим значением, указывающим, является ли i
простым, сделайте его числом, указывающим число способов, которыми оно не является простым , то есть число делителей i
.Для этого легко изменить основное сито Эратосфена: вместо того, чтобы установить sieve[x*y]
в false
, добавьте к нему 1.
Несколько последующих проблем Эйлера проекта выигрывают от аналогичного подхода.
Одна из проблем, с которой вы можете столкнуться, заключается в том, что в задаче 12 неясно, когда прекратить вычислять сито.Вы можете пойти двумя путями:
1. вычислить сито по частям по требованию, само по себе полезное упражнение по программированию (для этого потребуется более сложный код, чем второй метод)
2. или начать с завышение границы: найдите число треугольников с более чем 500 делителями, вы знаете, что остановитесь до или на этом числе.
Вы можете выиграть больше времени, если поймете, что вам нужно заботиться только онечетные числа, так как d (2 ^ k · n) = (k + 1) · d (n), если n нечетно, и поиск k и n только по заданным (2 ^ k · n) быстрым на двоичном компьютере.Я оставлю детали этой оптимизации в качестве упражнения.