https://projecteuler.net/problem=88
たくさんの素数から合成された数のほうがkが大きくなるのは明らかですが、小さい数から順に分解してkを求めるしかなさそうですね。
Mojoで謎のエラーが出て苦戦しました。次のように素因数分解構造体を次のようにするとどうしてもうまくいきません。
@value struct Pair[T: CollectionElement, U: CollectionElement]: var x: T var y: U alias Factor = Pair[Int, Int] @value struct Factors(Comparable): var fs: List[Factor] var value: Int
以下のようにしたらすんなり動きました。
from math import sqrt import sys #################### 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("[]") fn copy_list[T: CollectionElement](a: List[T]) -> List[T]: return sublist(a, 0, len(a)) fn sublist[T: CollectionElement](a: List[T], first: Int, last: Int) -> List[T]: var b = List[T]() for i in range(first, last): b.append(a[i]) return b fn connect_list[T: CollectionElement](a: List[T], b: List[T]) -> List[T]: var a1 = copy_list(a) a1.extend(b) return a1 #################### Pair #################### @value struct Pair[T: CollectionElement, U: CollectionElement]: var x: T var y: U #################### Factors #################### alias Factor = Pair[Int, Int] @value struct Factors(Comparable): var ps: List[Int] var es: List[Int] var value: Int fn __len__(self) -> Int: return len(self.ps) fn __lt__(self, other: Self) -> Bool: return self.value < other.value fn __le__(self, other: Self) -> Bool: return self.value <= other.value fn __eq__(self, other: Self) -> Bool: return self.value == other.value fn __ne__(self, other: Self) -> Bool: return self.value != other.value fn __gt__(self, other: Self) -> Bool: return self.value > other.value fn __ge__(self, other: Self) -> Bool: return self.value >= other.value fn is_prime(self) -> Bool: return len(self.ps) == 1 and self.es[0] == 1 @staticmethod fn divide_vec(es: List[Int]) -> List[List[Int]]: var L = len(es) var ess = List[List[Int]]() if L == 1: for e1 in range(es[0]+1): ess.append(List[Int](e1)) else: var mid = L // 2 var ess1 = Factors.divide_vec(sublist(es, 0, mid)) var ess2 = Factors.divide_vec(sublist(es, mid, L)) for es1 in ess1: for es2 in ess2: ess.append(connect_list(es1[], es2[])) return ess fn divide(self) -> List[Pair[Factors, Factors]]: var pairs = List[Pair[Factors, Factors]]() for es1_ in Factors.divide_vec(self.es): var ps1 = List[Int]() var ps2 = List[Int]() var es1 = List[Int]() var es2 = List[Int]() var value1 = 1 var value2 = 1 for i in range(len(self.ps)): var p = self.ps[i] var e1 = es1_[][i] var e2 = self.es[i] - e1 if e1 != 0: ps1.append(p) es1.append(e1) value1 *= p**e1 if e2 != 0: ps2.append(p) es2.append(e2) value2 *= p**e2 pairs.append(Pair[Factors, Factors](Factors(ps1, es1, value1), Factors(ps2, es2, value2))) return pairs @staticmethod fn make_min_factor_table(N: Int) -> List[Int]: var a = List[Int]() for n in range(N+1): a.append(n) for p in range(2, N+1): if p*p > N: break if a[p] != p: continue for n in range(p*p, N+1, p): if a[n] == n: a[n] = p return a @staticmethod fn factorize(n: Int, table: List[Int]) -> Factors: var m = n var ps = List[Int]() var es = List[Int]() var p = table[m] ps.append(p) es.append(1) m //= p while m > 1: p = table[m] if p == ps[len(ps)-1]: es[len(ps)-1] += 1 else: ps.append(p) es.append(1) m //= p return Factors(ps, es, n) #################### process #################### fn divide(fs: Factors) -> List[List[Int]]: var dss = List[List[Int]](List[Int](fs.value)) for pair in fs.divide(): var fs1 = pair[].x var fs2 = pair[].y if fs1.value == 1 or fs1.value > fs2.value: continue elif fs1.value <= fs2.value < fs1.value**2: dss.append(List[Int](fs1.value, fs2.value)) else: for ds2 in divide(fs2): if fs1.value <= ds2[][0]: var ds = connect_list(List[Int](fs1.value), ds2[]) dss.append(ds) return dss fn calc_k(ds: List[Int], owned n: Int) -> Int: for d in ds: n -= d[] return n + len(ds) fn f(N: Int) -> Int: var table = initialize_list(N+1, 0) var factor_table = Factors.make_min_factor_table(N*2) var set_ks = Set[Int]() for n in range(4, N*2+1): var fs = Factors.factorize(n, factor_table) if fs.is_prime(): continue for ds in divide(fs): if len(ds[]) == 1: continue var k = calc_k(ds[], n) if k <= N and table[k] == 0: table[k] = n set_ks.add(k) if len(set_ks) == N - 1: break var s: Int = 0 var used = Set[Int]() for k in range(2, N+1): var n = table[k] if n not in used: s += n used.add(n) return s fn main() raises: var args = sys.argv() var N = atol(args[1]) print(f(N))