2.ループの高速化


a についてのしらみつぶし探査は o(n) のオーダーなので、
桁数を 1 桁上げるために10倍の計算時間が必要になる。
何か工夫が欲しい。


b = a2 の下 n 桁の数字は、a の下 n 桁の数字のみによって決定される。
例えばある数 a について b = a 2を計算するとき、
b の下 5 桁で 4 種類以上の数字が出現すれば、それ以上、上の桁まで計算する意味はない。
そこで、例えば 1 ≤ g ≤ 99999 の g に対して、 g2 の下 5 桁の数字が 3 種類以下となる数だけを、配列 w(i) に格納しておき、

a = 100000 * h + w(i), h は任意

についてのみ調べる、という方法が考えられる。これで、かなりループの回数が減るはずである。

尚、初めの下 5 桁の数字のチェックで、前述のアルゴリズムを適用するには、多少工夫が必要である。
例えば a = 13 の時 a2=169=00169 なので下 5 桁は 4 種類の数字から成るが、len(169) = 3 だからループは3回で終わってしまい、3種類の数字から成る、と判定されてしまう。
00169 という形で判定したい。

これの回避方法は簡単で、例えば、探査範囲を100001 ≤ g ≤ 199999とし、下 5 桁のみに着目すればよい。


w(i) を格納する配列の要素数は減らすことができる。

(100000+g)2 = 1010 + 200000 g + g2
(100000-g)2 = 1010 - 200000 g + g2

であるから、100000+g と100000-g を 2 乗した場合、下 5 桁は一致する。
従って、g の範囲は、100001 ≤ g ≤ 149999 としてよい。
さらに、

(50000-g)2 = 25 * 108 - 100000 g + g2

であるから、g と 50000-g を 2 乗した場合、下 5 桁は一致する。
従って、g の範囲は、100001 ≤ g ≤ 124999 としてよい。
これで、配列の要素数は 1/4 で済む。
さらに、この範囲の数であれば、配列として整数型で桁数が足りる。

以上で、かなり高速化が期待できる。


アルゴリズムは以下のとおり。

    for g = 100001 to 124999
      下 5 桁の数字の判定。
      1. のアルゴリズムで、下位の桁から 5 桁分のみをチェックする
      3 文字以下なら、g@100000 を配列 w(i) に格納する
    next g

    h = 0
*   for i = 1 to m : a = 100000h + w(i) : gosub ** : next i
    for i = m to 1 step - 1 : a = 100000h + 50000 - w(i) : gosub ** : next i
    for i = 1 to m : a = 100000h + 50000 + w(i) : gosub ** : next i
    for i = m to 1 step - 1 : a = 100000h + 100000 - w(i) : gosub ** : next i
    inc h : goto *

**  ' サブルーチン
    a2 について、何種類の数字から構成されているかを調べる
    3 種類以下なら、a, b = a2 を表示する
    return

このアルゴリズムで求めた、a ≤ 109 以下の個別解は次頁のとおり。
(パターン解については、後でまとめて示す)


この章の目次

E-mail : kc2h-msm@asahi-net.or.jp
三島 久典