• Source
    1. #include <iostream>
    2. #include <cmath>
    3. #include <tuple>
    4. #include <chrono>
    5.  
    6. using namespace std;
    7.  
    8. // Calculates the divisors of an integer by determining its prime factorisation.
    9.  
    10. int get_divisors(long long n)
    11. {
    12. int divisors_count = 1;
    13.  
    14. for(long long i = 2;
    15. i <= sqrt(n);
    16. /* empty */)
    17. {
    18. int divisions = 0;
    19. while(n % i == 0)
    20. {
    21. n /= i;
    22. divisions++;
    23. }
    24.  
    25. divisors_count *= (divisions + 1);
    26.  
    27. //here, we try to iterate more efficiently by skipping
    28. //obvious non-primes like 4, 6, etc
    29. if(i == 2)
    30. i++;
    31. else
    32. i += 2;
    33. }
    34.  
    35. if(n != 1) //n is a prime
    36. return divisors_count * 2;
    37. else
    38. return divisors_count;
    39. }
    40.  
    41. long long euler12()
    42. {
    43. //n and n + 1
    44. long long n, n_p_1;
    45.  
    46. n = 1; n_p_1 = 2;
    47.  
    48. // divisors_x will store either the divisors of x or x/2
    49. // (the later iff x is divisible by two)
    50. long long divisors_n = 1;
    51. long long divisors_n_p_1 = 2;
    52.  
    53. for(;;)
    54. {
    55. /* This loop has been unwound, so two iterations are completed at a time
    56.   * n and n + 1 have no prime factors in common and therefore we can
    57.   * calculate their divisors separately
    58.   */
    59.  
    60. long long total_divisors; //the divisors of the triangle number
    61. // n(n+1)/2
    62.  
    63. //the first (unwound) iteration
    64.  
    65. divisors_n_p_1 = get_divisors(n_p_1 / 2); //here n+1 is even and we
    66.  
    67. total_divisors =
    68. divisors_n
    69. * divisors_n_p_1;
    70.  
    71. if(total_divisors > 1000)
    72. break;
    73.  
    74. //move n and n+1 forward
    75. n = n_p_1;
    76. n_p_1 = n + 1;
    77.  
    78. //fix the divisors
    79. divisors_n = divisors_n_p_1;
    80. divisors_n_p_1 = get_divisors(n_p_1); //n_p_1 is now odd!
    81.  
    82. //now the second (unwound) iteration
    83.  
    84. total_divisors =
    85. divisors_n
    86. * divisors_n_p_1;
    87.  
    88. if(total_divisors > 1000)
    89. break;
    90.  
    91. //move n and n+1 forward
    92. n = n_p_1;
    93. n_p_1 = n + 1;
    94.  
    95. //fix the divisors
    96. divisors_n = divisors_n_p_1;
    97. divisors_n_p_1 = get_divisors(n_p_1 / 2); //n_p_1 is now even!
    98. }
    99.  
    100. return (n * n_p_1) / 2;
    101. }
    102.  
    103. int main()
    104. {
    105. for(int i = 0; i < 5; i++)
    106. {
    107. using namespace std::chrono;
    108. auto start = high_resolution_clock::now();
    109. auto result = euler12();
    110. auto end = high_resolution_clock::now();
    111.  
    112. double time_elapsed = duration_cast<milliseconds>(end - start).count();
    113.  
    114. cout << result << " " << time_elapsed << '\n';
    115. }
    116. return 0;
    117. }