yukicoder 661, 662, 663, 664, 665
最近いろんな作業を Rust で書いてるんですが、Rust やってると Haskell が書きたくなってくる。664はまだです。
661 ハローキティはりんご3個分
import Control.Monad main = getLine >> getContents >>= mapM_ (putStrLn . solve . read) . lines solve n | n `mod` 40 == 0 = "ikisugi" | n `mod` 8 == 0 = "iki" | n `mod` 10 == 0 = "sugi" | otherwise = show (n `div` 3)
662 スロットマシーン
import Data.List import Data.Maybe import Control.Monad main = do dic <- replicateM 5 readKV (n1, a) <- readReel (map fst dic) (n2, b) <- readReel (map fst dic) (n3, c) <- readReel (map fst dic) -- [0] [1] [2] [3] [4] -- 000 0 0 -- 000 0 0 -- 000 0 0 let cnt = map (\k -> let x = a!!k; y = b!!k; z = c!!k in 5*x*y*z) $ [0..4] let ans = sum $ zipWith (*) cnt (map snd dic) print $ fromIntegral ans / fromIntegral (n1 * n2 * n3) mapM_ print cnt readKV :: IO (String, Int) readKV = do [k, v] <- words <$> getLine return (k, read v) readReel :: [String] -> IO (Int, [Int]) readReel dic = do n <- readLn :: IO Int x <- replicateM n (fromJust . flip elemIndex dic <$> getLine) return (n, [length . filter (==i) $ x | i <- [0..4]])
663 セルオートマトンの逆操作
リストモナドの bind を連鎖させれば全列挙できるけど、それだと指数時間になってしまう。bind 後に重複除去をすると計算量が落ちる(いまさらなんだけど、groupBy する前にソートしないと危険)。dp[i] から dp[i+1] が作れる系の DP はたいていこう書けると思う。
import Data.List import Control.Monad main = do n <- readLn :: IO Int a <- replicateM n readLn :: IO [Int] print $ solve a md :: Int md = 10^9 + 7 type Stat = (Int, Int, Int, Int) solve :: [Int] -> Int solve a = let b = foldl' g [((i, j, i, j), 1) | i <- [0,1], j <- [0,1]] a in modsum . map snd . filter (\((h1, h2, x, y), _) -> h1 == x && h2 == y) $ b where g :: [(Stat, Int)] -> Int -> [(Stat, Int)] g acc a = compress (acc >>= f a) f :: Int -> (Stat, Int) -> [(Stat, Int)] f a ((h1, h2, x, y), cnt) = [((h1, h2, y, z), cnt) | z <- [0, 1], rule x y z == a] compress :: [(Stat, Int)] -> [(Stat, Int)] compress a = map f . groupBy (\x y -> fst x == fst y) $ a where f :: [(Stat, Int)] -> (Stat, Int) f x = let key = fst (head x); val = modsum . map snd $ x in (key, val) modsum :: [Int] -> Int modsum = foldl' (\x y -> (x + y) `mod` md) 0 rule :: Int -> Int -> Int -> Int rule 0 0 0 = 0 rule 0 0 1 = 1 rule 0 1 0 = 1 rule 0 1 1 = 1 rule 1 0 0 = 0 rule 1 0 1 = 1 rule 1 1 0 = 1 rule 1 1 1 = 0
665 Bernoulli Bernoulli
F# だと演算子の優先順位がいい感じに自動生成されるんだけど、Haskell でその感覚でやったらハマった(どういう順序になってるんでしょう)。
import Data.List (foldl', scanl) md :: Int md = 10^9 + 7 -- sometimes ambigious infixl 6 +++ (+++) :: Int -> Int -> Int (+++) a b = (a + b) `mod` md infixl 7 *** (***) :: Int -> Int -> Int (***) a b = a * b `mod` md infixr 8 ^^^ (^^^) :: Int -> Int -> Int (^^^) a b | b == 0 = 1 | odd b = a *** a ^^^ (b - 1) | otherwise = (a *** a) ^^^ (b `div` 2) modinv :: Int -> Int modinv a = a ^^^ (md - 2) infixl 7 /// (///) :: Int -> Int -> Int (///) a b = a *** modinv b prodmod :: [Int] -> Int prodmod = foldl' (***) 1 -- p/(x-0) p/(x-1) -- vvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvv -- (x-1)(x-2)...(x-n+1) (x-0) (x-2)(x-3)...(x-n+1) -- --------------------- a[0] + ... ---------------------------- a[1] + ... -- (0-1)(0-2)...(0-n+1) (1-0) (1-2)(1-3)...(1-n+1) -- ^^^^^ ^^^^^^^^^^^^^^^^^^^^ -- [L] [R] lagrange :: [Int] -> Int -> Int lagrange a x | x < n = a !! x | otherwise = let (sm, _, _, _) = foldl' f (0, 0, 1, q) a in sm where n = length a p = prodmod [(x - i) | i <- [0..n-1]] q = prodmod [-i | i <- [1..n-1]] f :: (Int, Int, Int, Int) -> Int -> (Int, Int, Int, Int) f (sm, k, l, r) ak = (nextSm, k + 1, nextL, nextR) where nextSm = sm +++ ak *** p /// (l *** r *** (x-k)) nextL = l *** (k + 1) nextR = r /// negate (n - 1 - k) computeSmall :: Int -> [Int] computeSmall k = scanl f 0 [1..k + 1] where f s x = s +++ (x ^^^ k) solve :: Int -> Int -> Int solve n k = lagrange (computeSmall k) (n `mod` md) main = do [n, k] <- map read . words <$> getLine :: IO [Int] print $ solve n k