Problem32

30分プログラム、その305。Project Euler - Problem32

7254は面白い性質を持っている. 39 × 186 = 7254と書け, 掛けられる数/掛ける数/積に1から9の数が1回ずつ出現する.
掛けられる数/掛ける数/積に1から9の数が1回ずつ出現するような積の総和を求めよ.
HINT: いくつかの積は, 1通り以上の掛けられる数/掛ける数/積の組み合わせを持つが1回だけ数え上げよ.

いい方法が思いつかなかったので、力づくで解いてみた。

  • [1..9]を適当に並べ替えたリストLを作る。例えば、[3,9,1,8,6,7,2,5,4]
  • 適当な数字、a,bを選ぶ。ただしa < b。例えば、2と5。
  • Lをaとbの位置で分解する。lhs=39, rhs=186, res=7254
  • lhs*rhs=resかどうかを確認する

こうして、全てのresを求めたあと重複を削除してみた。遅いけど、まあ間違ってはいない。

使い方

$ time ./problem32
45228
./problem32  66.45s user 2.07s system 80% cpu 1:25.26 total

ソースコード

import Data.List
import Control.Monad.List

combination :: [Int] -> [[Int]]
combination [x] = [[x]]
combination xs = do x <- xs
                    rest <- combination $ delete x xs
                    return (x:rest)

makeInt xs = foldl (\x y->10*x+y) 0 xs

satisfy xs = do a <- [1..size-2]
                b <- [a+1..size-1]
                let (ys,res)  = splitAt b xs
                let (lhs,rhs) = splitAt a ys
                guard $ makeInt lhs * makeInt rhs == makeInt res
                return $ makeInt res
    where size = length xs

solve = do xs <- combination [1..9]
           x <- satisfy xs
           return x

main = print $ sum $ nub solve