順番に素因数分解を生成しても遅くないのですが、それでは面白くないので別の方法を考えましょう。4つの素数から成る数を昇順に生成すればよいのです。これは、約数の個数がある数より大きい自然数を昇順に列挙する(1)とほとんど同じです。初期の指数の並びが[1, 1, 1, 1]であるのと、項数が増えないことくらいです。
しかし、このくらいの数の大きさだと速度はほとんど変わらないです。
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.PriorityQueue import scala.collection.mutable.Set import Math.sqrt import scala.testing.Benchmark object Prime { val primes = new ArrayBuffer[Int] primes += 2 def apply(k :Int) = if(k < primes.size) primes(k) else { for(n <- Stream.from(primes(primes.size-1) + 1). takeWhile(n => k >= primes.size) if is_prime(n)) primes += n primes(primes.size-1) } def is_prime(n :Int) = primes.takeWhile(p => p * p <= n).forall(n % _ != 0) } def pow(n :Int, e :Int) = (1 to e).foldLeft(1L)((x, y) => x * n) def value(es :List[Int]) = es.zip(0 to (es.size - 1)).foldLeft(1L)( (x, y) => x * pow(Prime(y._2), y._1)) def num_divs(es :List[Int]) = es.foldLeft(1)((x, y) => x * (y + 1)) class gen_combinations(L :Int) extends Iterator[(Long,List[Int])] { val o = Ordering[Long].on[(Long,List[Int])](-_._1) val pq = new PriorityQueue[(Long,List[Int])]()(o) val init_es = List.range(0, L).map(k => 1) pq.enqueue((value(init_es), init_es)) def hasNext() = true def next() = { val (v0, es0) = pq.dequeue val es1 = (es0.head + 1) :: es0.tail pq.enqueue((value(es1), es1)) next_combination(Some(es0)).foreach(es => pq.enqueue((value(es), es))) println (v0, es0) (v0, es0) } def next_combination(es :Option[List[Int]]) :Option[List[Int]] = es match { case Some(e1 :: e2 :: tail) if e1 == e2 + 1 => Some(e1 :: e1 :: tail) case Some(e1 :: e2 :: tail) if e1 == e2 => next_combination(Some(e2 :: tail)).map(e2 :: _) case _ => None } } def is_descending(es :List[Int]) = es.zip(es.tail).forall(x => x._1 >= x._2) class gen_permutations(L :Int) extends Iterator[(Long,List[Int])] { val o = Ordering[Long].on[(Long,List[Int])](-_._1) val pq = new PriorityQueue[(Long,List[Int])]()(o) val g = (new gen_combinations(L)) val set_used = Set[Long]() put(g.next) def hasNext() = true def next() = { val (v0, es0) = pq.dequeue val ess = next_permutation(es0). filter(es => !set_used.contains(value(es))) for(es <- ess) put((value(es), es)) if(is_descending(es0)) pq.enqueue(g.next) (v0, es0) } private def put(x :(Long,List[Int])) = { pq.enqueue(x) set_used += x._1 } def next_permutation(es :List[Int]) :List[List[Int]] = es match { case (e1 :: e2 :: tail) if e1 > e2 => (e2 :: e1 :: tail) :: next_permutation(e2 :: tail).map(e1 :: _) case (e1 :: e2 :: tail) => next_permutation(e2 :: tail).map(e1 :: _) case _ => Nil } } class gen_numbers(L :Int) extends Iterator[Long] { val o = Ordering[Long].on[(Long,List[Int])](-_._1) val pq = new PriorityQueue[(Long,List[Int])]()(o) val g = new gen_permutations(L) pq.enqueue(g.next) def hasNext() = true def next() = { val (v0, es0) = pq.dequeue val rev_es0 = es0.reverse val rev_es1 = rev_es0.head :: 0 :: rev_es0.tail val es1 = rev_es1.reverse pq.enqueue((value(es1), es1)) if(es0.forall(0 !=)) pq.enqueue(g.next) next_value(es0).foreach(es => pq.enqueue((value(es), es))) v0 } def next_value(es :List[Int]) = { def f(es :Option[List[Int]]) :Option[List[Int]] = es match { case Some(0 :: 0 :: tail) => None case Some(0 :: e :: tail) => Some(e :: 0 :: tail) case Some(e :: tail) => f(Some(tail)).map(e :: _) case _ => None } f(Some(es.reverse)) match { case Some(a) => Some(a.reverse) case None => None } } } def find_solution(it :Iterator[Long], prev :Long, counter :Int = 0) :Long = if(counter == L) prev - L + 1 else { val v = it.next if(v != prev + 1) find_solution(it, v, 1) else find_solution(it, v, counter + 1) } def solve() = { val it :Iterator[Long] = new gen_numbers(L) println (find_solution(it, 0L)) } object Test extends Benchmark { def run() = solve } val L = 4 println (Test.runBenchmark(10))