Edited at

Haskell初学者がHaskellでAtCoder Beginners Selectionを半分解いた

AtCoder Beginners Selection

PracticeA - はじめてのあっとこーだー(Welcome to AtCoder)

import Control.Monad

import Control.Applicative
import Data.List.Split

main :: IO ()
main = do
input1 <- getLine
input2 <- getLine
input3 <- getLine
let num1 = read input1 :: Int
let nums = map read (splitOn " " input2) :: [Int]
let sum = num1 + (head nums) + (head $ tail nums)
let result = show sum
putStrLn (result ++ " " ++ input3)

標準入力、出力を覚える。

ABC086A - Product

import Control.Monad

import Control.Applicative
import Data.List.Split

result :: Int -> String
result n =
case even n of
True -> "Even"
False -> "Odd"

main :: IO ()
main = do
input <- getLine
let nums = map read (splitOn " " input) :: [Int]
let prod = (head nums) * (last nums)
putStrLn $ result prod

case分岐を覚える。

Haskellは nums[0] のように配列にアクセスすることはできないんだろうか。

ABC081A - Placing Marbles

import           Control.Applicative

import Control.Monad
import Data.List.Split

main :: IO ()
main = do
input <- getLine
let nums = map read (tail (splitOn "" input)) :: [Int]
let filtered = filter (\x -> case () of
_ | x == 1 -> True
| otherwise -> False) nums
putStrLn $ show $ length filtered

フォーマッターを当てることを覚える。

ラムダ式を使ってみる。


B - Shift only

B - Shift only

import           Control.Applicative

import Control.Monad
import Data.List.Split

getResult :: [Int] -> Int -> Int
getResult nums count
| 0 `elem` nums = count
| any odd nums = count
| otherwise = let
dividedNums = map (`div` 2) nums
newCount = count + 1
in
getResult dividedNums newCount

main :: IO ()
main = do
getLine
input <- getLine
let nums = map read (splitOn " " input) :: [Int]
let result = getResult nums 0
putStrLn $ show result

再帰を覚える。

手続き型だとwhileなど使いたくなる問題。


類題

B - Break Number

import           Control.Applicative

import Control.Monad
import Data.List.Split

getResult :: [Int] -> Int -> Int
getResult nums count = case filter even nums of
a | null a -> count
| otherwise -> getResult (map (`div` 2) a) count + 1

main :: IO ()
main = do
n <- readLn
print $ (^) 2 (getResult [1 .. n] 0)

B - Maximum Difference

import           Control.Applicative

import Control.Monad
import Data.List.Split

getResult :: [Int] -> Int
getResult nums = maximum nums - minimum nums

main :: IO ()
main = do
getLine
input <- getLine
let nums = map read (splitOn " " input) :: [Int]
print $ getResult nums


ABC087B - Coins

ABC087B - Coins

import           Control.Applicative

import Control.Monad
import Data.List.Split

getResult :: Int -> Int -> Int -> Int -> Int
getResult a b c x
= length [(s, t, u) | s<-[0..a], t<-[0..b], u<-[0..c]
, 500*s + 100*t + 50*u == x]

main :: IO ()
main = do
a <- readLn
b <- readLn
c <- readLn
x <- readLn
print $ getResult a b c x

手続き型だとforの3重ネストにして全探索、となるだろうが、「再帰でやればいいのか?」とちょっとわからなくなり調べた。

AtCoder に登録したら解くべき精選過去問 10 問を Haskell で解いてみた ($n+1$ 番煎じ)

こちらを参考に(というか丸写し)リスト内包表記を使用。


類題

B - Cakes and Donuts

import           Control.Applicative

import Control.Monad
import Data.List.Split

getResult :: Int -> Int
getResult n =
length [ (a, b) | a <- [0 .. n], b <- [0 .. n], 4 * a + 7 * b == n ]

main :: IO ()
main = do
n <- readLn
putStrLn $ if getResult n > 0 then "Yes" else "No"

B - Sum of Three Integers

import           Control.Applicative

import Control.Monad
import Data.List.Split

getResult :: Int -> Int -> Int
getResult k s = length
[ (x, y, z) | x <- [0 .. k], y <- [0 .. k], z <- [0 .. k], x + y + z == s ]

main :: IO ()
main = do
input <- getLine
let nums = map read (splitOn " " input) :: [Int]
print $ getResult (head nums) (last nums)

ただし実行時間が制限を超過する。