/**
* Problem 12
* ----------
* The sequence of triangle numbers is generated by adding the natural numbers.
* So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The
* first ten terms would be:
* 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
*
* Let us list the factors of the first seven triangle numbers:
* 1: 1
* 3: 1,3
* 6: 1,2,3,6
* 10: 1,2,5,10
* 15: 1,3,5,15
* 21: 1,3,7,21
* 28: 1,2,4,7,14,28
*
* We can see that 28 is the first triangle number to have over five divisors.
*
* What is the value of the first triangle number to have over five hundred
* divisors?
*/
#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <stdint.h>
typedef std:: map < uint64_t , uint64_t > Map;
Map get_prime_factors( uint64_t n) ;
template < typename T>
std:: ostream & operator<< ( std:: ostream & os, const std:: vector < T> & vec)
{
os << "{ " ;
for ( const auto & v : vec)
{
os << v << " " ;
}
return os << "}" ;
}
template < typename T>
std:: ostream & operator<< ( std:: ostream & os, const std:: map < T, T> & vec)
{
uint64_t c = 0 ;
for ( const auto & p : vec)
{
if ( c++ )
{
os << '*' ;
}
for ( uint64_t i = 0 ; i < p.second ; ++ i)
{
if ( i ! = 0 )
{
os << '*' ;
}
os << p.first ;
}
}
return os;
}
bool is_prime( uint64_t n, const std:: vector < uint64_t > & preceding)
{
// precondition: "preceding" contains all primes < sqrt(n)
for ( auto p : preceding)
{
if ( ( p * p) > n)
{
return true ;
}
if ( n % p == 0 )
{
return false ;
}
}
return true ;
}
uint64_t next_prime( std:: vector < uint64_t > & preceding)
{
if ( preceding.empty ( ) )
{
preceding.push_back ( 2 ) ;
return preceding.back ( ) ;
}
if ( preceding.back ( ) == 2 )
{
preceding.push_back ( 3 ) ;
return preceding.back ( ) ;
}
for ( uint64_t n = preceding.back ( ) + 2 ; ; n + = 2 )
{
if ( is_prime( n, preceding) )
{
preceding.push_back ( n) ;
return preceding.back ( ) ;
}
}
}
uint64_t num_divisors( uint64_t n)
{
uint64_t result = 1 ;
for ( auto pair : get_prime_factors( n) )
{
result * = ( pair.second + 1 ) ;
}
return result;
}
uint64_t triangle( uint64_t n)
{
return n % 2 == 0 ? ( n/ 2 ) * ( n+ 1 ) : ( ( n+ 1 ) / 2 ) * n;
}
Map operator+ ( Map lhs, const Map & rhs)
{
for ( auto p : rhs)
{
lhs[ p.first ] + = p.second ;
}
return lhs;
}
Map get_prime_factors( uint64_t n)
{
std:: map < uint64_t , uint64_t > result;
static std:: vector < uint64_t > pre = [ ] {
std:: vector < uint64_t > result;
for ( int i = 0 ; i < 15000 ; ++ i)
{
next_prime( result) ;
}
return result;
} ( ) ;
if ( n >= pre.size ( ) ) throw "n exceeds precalculated" ;
for ( uint64_t i = 0 ; i < pre.size ( ) ; ++ i)
{
auto p = pre[ i] ;
while ( n % p == 0 )
{
result[ p] ++ ;
n / = p;
}
if ( p > n)
{
return result;
}
}
return result;
}
Map get_prime_factors_of_tr( uint64_t n)
{
if ( n% 2 == 0 )
{
return get_prime_factors( n/ 2 ) + get_prime_factors( n + 1 ) ;
}
else
{
return get_prime_factors( n) + get_prime_factors( ( n + 1 ) / 2 ) ;
}
}
uint64_t get_divisors_count_of_tr( uint64_t n)
{
uint64_t result = 1 ;
for ( auto pair : get_prime_factors_of_tr( n) )
{
result * = pair.second + 1 ;
}
return result;
}
class Stopwatch
{
public :
typedef std:: chrono :: high_resolution_clock Clock;
//! Constructor starts the stopwatch
Stopwatch( ) : mStart( Clock:: now ( ) )
{
}
//! Returns elapsed number of seconds in decimal form.
double elapsed( )
{
return 1.0 * ( Clock:: now ( ) - mStart) .count ( ) / Clock:: period :: den ;
}
Clock:: time_point mStart;
} ;
int main( )
{
Stopwatch sw;
for ( uint64_t i = 2 ; ; ++ i)
{
auto div = get_divisors_count_of_tr( i) ;
if ( div > 500 )
{
std:: cout << triangle( i) << std:: endl ;
break ;
}
}
std:: cout << ( 1000 * sw.elapsed ( ) ) << "ms" << std:: endl ;
}
LyoqCiAqIFByb2JsZW0gMTIKICogLS0tLS0tLS0tLQogKiBUaGUgc2VxdWVuY2Ugb2YgdHJpYW5nbGUgbnVtYmVycyBpcyBnZW5lcmF0ZWQgYnkgYWRkaW5nIHRoZSBuYXR1cmFsIG51bWJlcnMuCiAqIFNvIHRoZSA3dGggdHJpYW5nbGUgbnVtYmVyIHdvdWxkIGJlIDEgKyAyICsgMyArIDQgKyA1ICsgNiArIDcgPSAyOC4gVGhlCiAqIGZpcnN0IHRlbiB0ZXJtcyB3b3VsZCBiZToKICogICAxLCAzLCA2LCAxMCwgMTUsIDIxLCAyOCwgMzYsIDQ1LCA1NSwgLi4uCiAqCiAqIExldCB1cyBsaXN0IHRoZSBmYWN0b3JzIG9mIHRoZSBmaXJzdCBzZXZlbiB0cmlhbmdsZSBudW1iZXJzOgogKiAgIDE6IDEKICogICAzOiAxLDMKICogICA2OiAxLDIsMyw2CiAqICAgMTA6IDEsMiw1LDEwCiAqICAgMTU6IDEsMyw1LDE1CiAqICAgMjE6IDEsMyw3LDIxCiAqICAgMjg6IDEsMiw0LDcsMTQsMjgKICoKICogV2UgY2FuIHNlZSB0aGF0IDI4IGlzIHRoZSBmaXJzdCB0cmlhbmdsZSBudW1iZXIgdG8gaGF2ZSBvdmVyIGZpdmUgZGl2aXNvcnMuCiAqCiAqIFdoYXQgaXMgdGhlIHZhbHVlIG9mIHRoZSBmaXJzdCB0cmlhbmdsZSBudW1iZXIgdG8gaGF2ZSBvdmVyIGZpdmUgaHVuZHJlZAogKiBkaXZpc29ycz8KICovCgoKI2luY2x1ZGUgPGFsZ29yaXRobT4KI2luY2x1ZGUgPGNocm9ubz4KI2luY2x1ZGUgPGNtYXRoPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxtYXA+CiNpbmNsdWRlIDx2ZWN0b3I+CiNpbmNsdWRlIDxzdGRpbnQuaD4KCgoKdHlwZWRlZiBzdGQ6Om1hcDx1aW50NjRfdCwgdWludDY0X3Q+IE1hcDsKTWFwIGdldF9wcmltZV9mYWN0b3JzKHVpbnQ2NF90IG4pOwoKCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnN0ZDo6b3N0cmVhbSYgb3BlcmF0b3I8PChzdGQ6Om9zdHJlYW0gJiBvcywgY29uc3Qgc3RkOjp2ZWN0b3I8VD4gJiB2ZWMpCnsKICAgIG9zIDw8ICJ7ICI7CiAgICBmb3IgKGNvbnN0IGF1dG8gJiB2IDogdmVjKQogICAgewogICAgICAgIG9zIDw8IHYgPDwgIiAiOwogICAgfQogICAgcmV0dXJuIG9zIDw8ICJ9IjsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RkOjpvc3RyZWFtJiBvcGVyYXRvcjw8KHN0ZDo6b3N0cmVhbSAmIG9zLCBjb25zdCBzdGQ6Om1hcDxULCBUPiAmIHZlYykKewogICAgdWludDY0X3QgYyA9IDA7CiAgICBmb3IgKGNvbnN0IGF1dG8gJiBwIDogdmVjKQogICAgewogICAgICAgIGlmIChjKyspCiAgICAgICAgewogICAgICAgICAgICBvcyA8PCAnKic7CiAgICAgICAgfQogICAgICAgIGZvciAodWludDY0X3QgaSA9IDA7IGkgPCBwLnNlY29uZDsgKytpKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKGkgIT0gMCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgb3MgPDwgJyonOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG9zIDw8IHAuZmlyc3Q7CiAgICAgICAgfQogICAgfQogICAgcmV0dXJuIG9zOwp9CgoKYm9vbCBpc19wcmltZSh1aW50NjRfdCBuLCBjb25zdCBzdGQ6OnZlY3Rvcjx1aW50NjRfdD4gJiBwcmVjZWRpbmcpCnsKICAgIC8vIHByZWNvbmRpdGlvbjogInByZWNlZGluZyIgY29udGFpbnMgYWxsIHByaW1lcyA8IHNxcnQobikKCiAgICBmb3IgKGF1dG8gcCA6IHByZWNlZGluZykKICAgIHsKICAgICAgICBpZiAoKHAgKiBwKSA+IG4pCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CgogICAgICAgIGlmIChuICUgcCA9PSAwKQogICAgICAgIHsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgIH0KICAgIHJldHVybiB0cnVlOwp9CgoKdWludDY0X3QgbmV4dF9wcmltZShzdGQ6OnZlY3Rvcjx1aW50NjRfdD4gJiBwcmVjZWRpbmcpCnsKICAgIGlmIChwcmVjZWRpbmcuZW1wdHkoKSkKICAgIHsKICAgICAgICBwcmVjZWRpbmcucHVzaF9iYWNrKDIpOwogICAgICAgIHJldHVybiBwcmVjZWRpbmcuYmFjaygpOwogICAgfQoKICAgIGlmIChwcmVjZWRpbmcuYmFjaygpID09IDIpCiAgICB7CiAgICAgICAgcHJlY2VkaW5nLnB1c2hfYmFjaygzKTsKICAgICAgICByZXR1cm4gcHJlY2VkaW5nLmJhY2soKTsKICAgIH0KCiAgICBmb3IgKHVpbnQ2NF90IG4gPSBwcmVjZWRpbmcuYmFjaygpICsgMjsgOyBuICs9IDIpCiAgICB7CiAgICAgICAgaWYgKGlzX3ByaW1lKG4sIHByZWNlZGluZykpCiAgICAgICAgewogICAgICAgICAgICBwcmVjZWRpbmcucHVzaF9iYWNrKG4pOwogICAgICAgICAgICByZXR1cm4gcHJlY2VkaW5nLmJhY2soKTsKICAgICAgICB9CiAgICB9Cn0KCgp1aW50NjRfdCBudW1fZGl2aXNvcnModWludDY0X3QgbikKewogICAgdWludDY0X3QgcmVzdWx0ID0gMTsKICAgIGZvciAoYXV0byBwYWlyIDogZ2V0X3ByaW1lX2ZhY3RvcnMobikpCiAgICB7CiAgICAgICAgcmVzdWx0ICo9IChwYWlyLnNlY29uZCArIDEpOwogICAgfQogICAgcmV0dXJuIHJlc3VsdDsKfQoKCnVpbnQ2NF90IHRyaWFuZ2xlKHVpbnQ2NF90IG4pCnsKICAgIHJldHVybiBuICUgMiA9PSAwID8gKG4vMikgKiAobisxKSA6ICgobisxKS8yKSAqIG47Cn0KCgoKTWFwIG9wZXJhdG9yKyhNYXAgbGhzLCBjb25zdCBNYXAgJiByaHMpCnsKICAgIGZvciAoYXV0byBwIDogcmhzKQogICAgewogICAgICAgIGxoc1twLmZpcnN0XSArPSBwLnNlY29uZDsKICAgIH0KICAgIHJldHVybiBsaHM7Cn0KCgpNYXAgZ2V0X3ByaW1lX2ZhY3RvcnModWludDY0X3QgbikKewogICAgc3RkOjptYXA8dWludDY0X3QsIHVpbnQ2NF90PiByZXN1bHQ7CiAgICBzdGF0aWMgc3RkOjp2ZWN0b3I8dWludDY0X3Q+IHByZSA9IFtdewogICAgICAgIHN0ZDo6dmVjdG9yPHVpbnQ2NF90PiByZXN1bHQ7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCAxNTAwMDsgKytpKQogICAgICAgIHsKICAgICAgICAgICAgbmV4dF9wcmltZShyZXN1bHQpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgfSgpOwoKICAgIGlmIChuID49IHByZS5zaXplKCkpIHRocm93ICJuIGV4Y2VlZHMgcHJlY2FsY3VsYXRlZCI7CgogICAgZm9yICh1aW50NjRfdCBpID0gMDsgaSA8IHByZS5zaXplKCk7ICsraSkKICAgIHsKICAgICAgICBhdXRvIHAgPSBwcmVbaV07CiAgICAgICAgd2hpbGUgKG4gJSBwID09IDApCiAgICAgICAgewogICAgICAgICAgICByZXN1bHRbcF0rKzsKICAgICAgICAgICAgbiAvPSBwOwogICAgICAgIH0KICAgICAgICBpZiAocCA+IG4pCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgIH0KICAgIHJldHVybiByZXN1bHQ7Cn0KCgpNYXAgZ2V0X3ByaW1lX2ZhY3RvcnNfb2ZfdHIodWludDY0X3QgbikKewogICAgaWYgKG4lMiA9PTApCiAgICB7CiAgICAgICAgcmV0dXJuIGdldF9wcmltZV9mYWN0b3JzKG4vMikgKyBnZXRfcHJpbWVfZmFjdG9ycyhuICsgMSk7CiAgICB9CiAgICBlbHNlCiAgICB7CiAgICAgICAgcmV0dXJuIGdldF9wcmltZV9mYWN0b3JzKG4pICsgZ2V0X3ByaW1lX2ZhY3RvcnMoKG4gKyAxKS8yKTsKICAgIH0KfQoKCnVpbnQ2NF90IGdldF9kaXZpc29yc19jb3VudF9vZl90cih1aW50NjRfdCBuKQp7CiAgICB1aW50NjRfdCByZXN1bHQgPSAxOwogICAgZm9yIChhdXRvIHBhaXIgOiBnZXRfcHJpbWVfZmFjdG9yc19vZl90cihuKSkKICAgIHsKICAgICAgICByZXN1bHQgKj0gcGFpci5zZWNvbmQgKyAxOwogICAgfQogICAgcmV0dXJuIHJlc3VsdDsKfQoKCmNsYXNzIFN0b3B3YXRjaAp7CnB1YmxpYzoKICAgIHR5cGVkZWYgc3RkOjpjaHJvbm86OmhpZ2hfcmVzb2x1dGlvbl9jbG9jayBDbG9jazsKCiAgICAvLyEgQ29uc3RydWN0b3Igc3RhcnRzIHRoZSBzdG9wd2F0Y2gKICAgIFN0b3B3YXRjaCgpIDogbVN0YXJ0KENsb2NrOjpub3coKSkKICAgIHsKICAgIH0KCiAgICAvLyEgUmV0dXJucyBlbGFwc2VkIG51bWJlciBvZiBzZWNvbmRzIGluIGRlY2ltYWwgZm9ybS4KICAgIGRvdWJsZSBlbGFwc2VkKCkKICAgIHsKICAgICAgICByZXR1cm4gMS4wICogKENsb2NrOjpub3coKSAtIG1TdGFydCkuY291bnQoKSAvIENsb2NrOjpwZXJpb2Q6OmRlbjsKICAgIH0KCiAgICBDbG9jazo6dGltZV9wb2ludCBtU3RhcnQ7Cn07CgoKaW50IG1haW4oKQp7CiAgICBTdG9wd2F0Y2ggc3c7CiAgICBmb3IgKHVpbnQ2NF90IGkgPSAyOyA7ICsraSkKICAgIHsKICAgICAgICBhdXRvIGRpdiA9IGdldF9kaXZpc29yc19jb3VudF9vZl90cihpKTsKICAgICAgICBpZiAoZGl2ID4gNTAwKQogICAgICAgIHsKICAgICAgICAgICAgc3RkOjpjb3V0IDw8IHRyaWFuZ2xlKGkpIDw8IHN0ZDo6ZW5kbDsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgfQogICAgc3RkOjpjb3V0IDw8ICgxMDAwICogc3cuZWxhcHNlZCgpKSA8PCAibXMiIDw8IHN0ZDo6ZW5kbDsKfQo=