12問目
三角数からなる数列は, 自然数を次々と足していくことで得られる. 7番目の三角数は になる. 数列の最初の10項は,
となる.三角数の最初の7項について約数を列挙すると,
となる.
これから, 28 が約数の数が5を越える最小の三角数だと分かる.では, 約数の数が 50 を越える最小の三角数はいくつか?
http://projecteuler.net/index.php?section=problems&id=12
最初は数学を使って考察. 計算量を減らしていきます.
一般に三角数は と表せるが,
のとき, ,
のとき,
となる. よって,
となる. ( は, の正の約数の個数. )
これを踏まえてコーディング.
#include <stdio.h> #include <math.h> #include <stdlib.h> #include <limits.h> #include "prime.h" const int LIMIT = 500; const int NUM_LIMIT = LONG_MAX; long long solveVer00(); long numDivisors(long); int main(int argc, char **argv) { initPrime(); fprintf(stdout, "Solution: %lld\n", solveVer00()); return 0; } long long solveVer00() { long n; for (n = 1; n < NUM_LIMIT; n++) { if ((n % 2) == 0) { if (numDivisors(n/2) * numDivisors(n+1) > LIMIT) { return (long long) (n / 2) * (n + 1); } } else { if (numDivisors(n) * numDivisors((n+1)/2) > LIMIT) { return (long long) n * (n + 1) / 2; } } } return 0; } long numDivisors(long number) { long long p; int power; long result; prime(-1); result = 1; while (number > 1 && (p = prime(0)) != -1) { power = 0; while ((number % p) == 0) { number /= p; power++; } result *= power + 1; } return result; }
この問題を機に書き直した素数関連の関数たちはこちら.
#include "prime-2.0.h" #define SIZE 1000000 static int numbers[SIZE]; static int primes[SIZE]; const int NOT_PRIME = 0; const int PRIME = 1; /** * numbers, primes の初期化 */ void initPrime() { long i; long numberIndex; long primeIndex; numbers[0] = NOT_PRIME; numbers[1] = NOT_PRIME; for (numberIndex = 2; numberIndex < SIZE; numberIndex++) { numbers[numberIndex] = PRIME; } for (primeIndex = 0; primeIndex < SIZE; primeIndex++) { primes[primeIndex] = NOT_PRIME; } for (numberIndex = 2, primeIndex = 0; numberIndex < SIZE; numberIndex++) { if (numbers[numberIndex] == PRIME) { for (i = 2; i * numberIndex < SIZE; i++) { numbers[i * numberIndex] = NOT_PRIME; } primes[primeIndex] = numberIndex; primeIndex++; } } } /** * 小さい方から value 番目の素数を返す. * 0 を入れると小さい方から順々に素数を返す. * -1 を入れることでリセットでき, 再び2から返していく. * インデックスが大きすぎる場合は -1 を返す. */ long long prime(long long value) { static long long primeIndex = 0; if (value > SIZE) { return -1; } if (value == -1) { primeIndex = 0; return 0; } else if (value == 0) { return primes[primeIndex++]; } else if (value > 0) { return primes[value]; } else { return -1; } } int isPrime(long long value) { return numbers[value] == PRIME; }