MojoでProject Euler 75

https://projecteuler.net/problem=75

直角三角形の辺は、
 a = l(m^2-n^2)\ b = 2lmn\ c = l(m^2+n^2)\ (m, n) = 1\ n \lt m
と表されるので、周囲の長さLは、
 L = a + b + c = 2lm(m+n)\ (m, m+n) = 1\ m \lt m+n \lt 2m\ m+n: odd
となります。なので、 l, m, nを当てはめていけばよいです。
計算量は、たぶん O(L_{upper}(\log{L_{upper}})^2)くらいです。
 L_{upper} = 5 \times 10^8くらいだと間に合いますね。ただし、その分メモリを食います。

この方法ではいきなり直角三角形が一つしかないLを求められないですが、直接求める方法もあります。 L = 2^e \cdot 3とすると、必ず m+n = 3になるので、 m = 2となって、残りが l = 2^{e-2}です。すなわち、 e \ge 2なら直角三角形が一つだけになります。また、 L = 12p\ (p: prime)のとき、 p \gt 12なら、まず m+n = 3だと n = 2で残りが l = pという直角三角形があります。 m+n = p m+n = 3pも考えられますが、これだとnが十分に大きくならないので、必ず直角三角形は一つになります。これだと、 p \le L_{upper}/12は全て成り立つので、素数の個数を数えるだけです。このようにすれば直接数えることができますが、最初の方法より速くなりませんでした。

import sys


#################### library ####################

fn gcd(n: Int, m: Int) -> Int:
    if m == 0:
        return n
    else:
        return gcd(m, n % m)


#################### List ####################

fn initialize_list[T: CollectionElement](N: Int, init: T) -> List[T]:
    var a = List[T](capacity=N)
    for n in range(N):
        a.append(init)
    return a

trait Printable(CollectionElement, Stringable):
    pass

fn print_list[T: Printable](a: List[T]):
    if a.size > 0:
        var s = "[" + str(a[0])
        for i in range(1, a.size):
            s += ", " + str(a[i])
        s += "]"
        print(s)
    else:
        print("[]")


#################### process ####################

fn f(L: Int) -> Int:
    var freq = initialize_list(L+1, 0)
    for l in range(1, L/12+1):
        var n1 = L // (2 * l)
        for m in range(2, n1):
            if m * (m + 1) > n1:
                break
            var nm0 = (m + 1) // 2 * 2 + 1
            var n2 = n1 // m
            for nm in range(nm0, min(n2+1, m*2), 2):
                if gcd(m, nm) != 1:
                    continue
                var p = 2 * l * m * nm
                freq[p] += 1
    
    var counter = 0
    for i in range(1, L+1):
        if freq[i] == 1:
            counter += 1
    return counter

fn main() raises:
    var args = sys.argv()
    var L = atol(args[1])
    print(f(L))