Codeforces 146B - B. Lucky Mask

146B - B. Lucky Mask

整数 a, b が与えられたとき、c のマスクが b と等しく、かつ c > a であるような c を求めよという問題。

「c のマスクが b と等しい」とは、整数 c から 4 と 7 以外の数字を取り除いた数が b と等しいという意味。

制約:
1 <= a, b <= 10^5

全探索。

mask :: Int -> Int    
mask n | null s    = 0
       | otherwise = read s
  where
    s = filter (\c -> c == '4' || c == '7') $ show n

calc :: Int -> Int -> Int
calc a b = head [i | i <- [a+1..], b == mask i]

main = do s <- getLine
          let [a, b] = map read $ words s :: [Int]
          print $ calc a b

はじめにmask関数を書いたとき、if式を用いていたけど、ガードに書き直した。ガードの方が読みやすく分かりやすい。

mask :: Int -> Int    
mask n = if null s
         then 0
         else read s
  where
    s = filter (\c -> c == '4' || c == '7') $ show n

Codeforces 26A - A. Almost Prime

26A - A. Almost Prime

素因数分解したときに、素因数の種類が 2 つかどうか求める問題。

import Data.List

factorize :: Int -> [Int]
factorize 1 = [1]
factorize n = fac 2 n
  where
    fac p n
      | n == 1         = []
      | n `mod` p == 0 = p : fac p (n `div` p)
      | otherwise      = fac (p+1) n

isAlmostPrime :: Int -> Bool
isAlmostPrime n = 2 == (length $ nub $ factorize n)

calc :: Int -> Int
calc n = sum [1 | i <- [1..n], isAlmostPrime i]

main = do s <- getLine
          print $ calc $ read s

リストの中にpredを満たすものがいくつあるか個数を返す関数が標準ライブラリにありそうだと思って調べたけれど見つかりませんでした。

Codeforces 148A - A. Insomnia cure

148A - A. Insomnia cure

calc :: Int -> Int -> Int -> Int -> Int -> Int
calc k l m n d = d - length [i | i <- [1..d],
                             i `mod` k /= 0,
                             i `mod` l /= 0,
                             i `mod` m /= 0,
                             i `mod` n /= 0]

main = do s <- getContents
          let [k, l, m, n, d] = map read $ lines s :: [Int]
          print $ calc k l m n d

英文の読み方

英文が難しいけど、意味が分からないところは読み飛ばして最後まで読んでみる。それからまたはじめに戻って全体を読み返す。それを何度か繰り返すと、なんとなく意味がつかめてくる箇所が出てくる(分からないままのことも多いけど)。それから入力と出力のサンプルも確認する。入出力は問題文の意味を読み解くヒントになることも少なくない。

Codeforces 3A - A. Shortest path of the king

3A - A. Shortest path of the king

import Data.Char      

parse :: String -> (Int, Int)
parse s = (digitToInt (s!!1), ord (s!!0) - ord 'a' + 1)

calc :: (Int, Int) -> (Int, Int) -> [String]
calc (sr, sc) (dr, dc)
  | sr == dr && sc == dc = []
  | otherwise =  dir : calc (r, c) (dr, dc)
    where
      r = sr + signum (dr - sr)
      c = sc + signum (dc - sc)
      dir = (move sc dc "R" "L") ++ (move sr dr "U" "D")
      move src dst lt gt
        | src == dst = ""
        | src <  dst = lt
        | otherwise  = gt

main :: IO ()       
main = do s <- getLine
          t <- getLine
          let moves = calc (parse s) (parse t)
          print $ length moves
          mapM_ putStrLn moves

mapM_ はまだよく意味が分かっていない。

参考:

Codeforces 139A - A. Petr and Book

139A - A. Petr and Book

calc :: Int -> [Int] -> Int
calc n pages = calc' n (cycle pages) (cycle [1..7])
  where
    calc' n (p:pages) (d:dayWeek)
      | n <= p    = d
      | otherwise = calc' (n-p) pages dayWeek

main = do s <- getLine
          t <- getLine
          print $ calc (read s) (map read $ words t)

Codeforces 146A - A. Lucky Ticket

146A - A. Lucky Ticket

import Data.Char

isLucky :: String -> Bool
isLucky s = all (\c -> c == '4' || c == '7') s

calc :: String -> String
calc s = if isLucky s && sum hd == sum tl
         then "YES"
         else "NO"
  where
    xs = map digitToInt s 
    n  = length s `div` 2
    hd = take n xs
    tl = drop n xs

main = do s <- getLine
          t <- getLine
          putStrLn $ calc t