ScalaでProject Euler(55)

Problem 31

場合の数ですね。場合の数や確率を求める問題は、まず母関数の手法が使えるかどうか考えたほうが良いです。この問題はわかりやすいです。

Pk(x) = 1 + xk + x2k + ...

という母関数を考えます。各係数はkペンスだけ使ったときの場合の数です。例えば、k = 5として、x10の係数は1だから1通り、x11の係数は0だからそんな組合せはありません。また、

P1(x)P2(x) = (1 + x + x2 + x3 + ...)(1 + x2 + ...) = 1 + x + 2x2 + 2x3 + ...

x3の係数の2は、(1p, 2p), (1p, 1p, 1p)の2通りを表しています。
この問題は、

P1(x)P2(x)P5(x)...P200(x)

x200の係数を求めるだけです。

type Poly = Array[Int]

val N = 200
val coins = List(1, 2, 5, 10, 20, 50, 100, 200)

def series(c :Int) =
    Array.range(0, N + 1).map(k => if(k % c == 0) 1 else 0)

def mul(f :Poly, g :Poly) = {
    val a = new Poly(N + 1)
    for(k <- Iterator.range(0, N + 1); l <- Iterator.range(0, N - k + 1))
        a(k + l) += f(k) * g(l)
    a
}

def unit() : Array[Int]=
    Iterator.range(0, N + 1).map(k => if(k == 0) 1 else 0).toArray

val f = coins.map(series).foldLeft(unit)(mul)
println (f(N))