三角数は六角数を含むので、三角数は考えなくてもよいことになります。
単に五角数と六角数を昇順に並べてマージ法を使うのが簡単でしょう。
// Polygonal number def P(p :Int) :Stream[Long] = Stream.from(1).map(n => n * ((p - 2L) * n - p + 4) / 2) def coincident(s1 :Stream[Long], s2 :Stream[Long]) :Stream[Long] = (s1, s2) match { case (h1 #:: t1, h2 #:: t2) if h1 < h2 => coincident(t1, s2) case (h1 #:: t1, h2 #:: t2) if h1 > h2 => coincident(s1, t2) case (h1 #:: t1, h2 #:: t2) => h1 #:: coincident(t1, s2) case _ => Stream() } println (coincident(P(5), P(6)).take(3).toList)
しかし、数学を使うと速くなります。
Pm = Hn
m(3m - 1) / 2 = n(2n - 1)
36m2 - 12m = 3(16n2 - 8n)
(6m - 1)2 - 1 = 3(4n - 1)2 - 3
(6m - 1)2 - 3(4n - 1)2 = -2
この式で、
x = 6m - 1
y = 4n - 1
と置くと、
x2 - 3y2 = -2
となり、ほぼペル方程式で、
xk + yk√3 = (2 + √3)k(1 + √3)
と計算できます。このうち、
xk ≡ -1(mod 6)
yk ≡ -1(mod 4)
を満たすものが解です。
def gen_Pell() = { // (2 + √3)^n(1 + √3) def next(xy :(Int,Int)) = { val (x, y) = xy (2 * x + 3 * y, x + 2 * y) } Iterator.iterate((1, 1))(next) } val it_sol = for((x, y) <- gen_Pell if x % 6 == 5 && y % 4 == 3; m = (x + 1) / 6) yield m * (3L * m - 1) / 2 println (it_sol.take(3).toList)