問題141をやってみた

メインから。
時間を計るので、ちょいゴタゴタしてます。
1兆までなのでかなり時間がかかります。
いえ、力技コードなので処理時間は気にしてないですw

#include <iostream>
#include <chrono>

int main()
{
    long long limit = 1000000000000;

    std::chrono::system_clock::time_point start;
    std::chrono::system_clock::time_point end;

    start = std::chrono::system_clock::now();
    long long answer = solve(limit);
    end = std::chrono::system_clock::now();
    long long elasped = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();

    std::cout << "tims: " << elasped << " answer: " << answer << std::endl;
}

次は solve。

static long long solve(long long limit)
{
    long long sum = 0;

    for (long long n = 1; n * n < limit; n++)
    {
        if (isRuishinNumber(n))
        {
            std::cout << n * n << std::endl;
            sum += n * n;
        }
    }

    return sum;
}

n * n を使うのですが n も用意しておくのは sqrt() とか使って誤差が出るのを避けるためです。

最後は isRuishinNumber。

static bool isRuishinNumber(long long n)
{
    long long nn = n * n;
    for (long long d = 2; d < n; d++)
    {
        long long q = (long long)floor((double)nn / (double)d);
        long long r = nn - d * q;

        if (r == 0)
        {
            continue;
        }

        if (d * d == q * r)
        {
            return true;
        }
    }

    return false;
}

d は 2 から n (nn の平方根) 未満まで走査します。d=1 だと r が 0 に、d=n だと d と q が n になるため累進数の条件を満たしません。
さらに、d > n を計算しても d と q が入れ替わるだけなので計算は不要です。

r は「%」を使用せず、nn - d * q と四則演算のみで求めます。こちらのほうが処理が速いです。
また、r が 0 の場合は、d, q, r は幾何数列にならないので、さっさと次の処理を実行するようにします。

d, q, r の関係は、d は n (nn の平方根)より小さいため、かならず q > d となります。
また、nn を d で割った余りが r なので、かならず d > r となります。
つまり

q > d > r > 0

という関係になります。
また、q, d, r が幾何数列にならなければいけないので、

q : d = d : r

と書くことが出来ます。公比は特に求める必要はありません。
比例式は内項の積と外項の積が等しくなります。つまり、

d * d = q * r

これが q, d, r が幾何数列になる条件となります。
ここも除算を使用すると誤差が出てしまい、正しく判定できない可能性がありますから、
整数の乗算で判定するようにしています。これならば誤差の心配はいりません。

実行結果

9
10404
16900
97344
576081
6230016
7322436
12006225
36869184
37344321
70963776
196112016
256160025
1361388609
1380568336
8534988225
9729849600
12551169024
13855173264
16394241600
123383587600
142965659664
547674002500
tims: 3681753496 answer: 878454337159

答えは 878454337159 となります。
処理時間は 1 時間ぐらいかかっていますw

問題に正解すると Project Euler の公式ページのフォーラムが閲覧できるようになり、みんなが解いたプログラムを拝見することができ、プログラムのロジックの解説が書いてあったり、質問したり議論もできるようになっています。計算で瞬時(数ミリ秒)で解いてしまうすごいプログラムや、独特な面白いプログラムが掲載されていたりするので、すごく勉強になります。