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

[AtCoder Beginners Selection](https://atcoder.jp/contests/abs)

[PracticeA - はじめてのあっとこーだー（Welcome to AtCoder）](https://atcoder.jp/contests/abs/tasks/practice_1)

```haskell
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](https://atcoder.jp/contests/abs/tasks/abc086_a)

```haskell
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](https://atcoder.jp/contests/abs/tasks/abc081_a)

```haskell
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](https://atcoder.jp/contests/abc081/tasks/abc081_b)

```haskell
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](https://atcoder.jp/contests/abc068/tasks/abc068_b)

```haskell
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](https://atcoder.jp/contests/abc102/tasks/abc102_b)

```haskell
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](https://atcoder.jp/contests/abs/tasks/abc087_b)

```haskell
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$ 番煎じ）](https://qiita.com/bra_cat_ket/items/da0f1ddeeccfc129dadb)

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

## 類題

[B - Cakes and Donuts](https://atcoder.jp/contests/abc105/tasks/abc105_b)

```haskell
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](https://atcoder.jp/contests/abc051/tasks/abc051_b)

```haskell
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)
```

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