AtCoder Beginner Contest 355 振り返り

ABC355の振り返りです。久しぶりの投稿です。（すみませんサボってました）

## 今回の結果

A,Bの2完でした。

![スクリーンショット 2024-06-01 9.19.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/a2e39a21-9a50-36ec-7093-cbcfc96962a5.png)

![スクリーンショット 2024-06-01 9.20.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/78d0ee5a-ed53-2424-9e66-25895f7bf44c.png)

## 各問題の振り返り

### A - Who Ate the Cake?!

- [問題文](https://atcoder.jp/contests/abc355/tasks/abc355_a)
- [自分の回答](https://atcoder.jp/contests/abc355/submissions/53837225)

1, 2, 3のうちいずれか2つの値を受け取り、残りの値が1意に決まるかどうかを問う問題です。
`[1, 2, 3]`のリストを作っておき、入力を除外した値が1を超えるなら`-1`を、そうでないならその値を出力します。

```haskell
main :: IO ()
main = do
  ab <- readPairInt
  let ans = L.filter (\i -> i /= fst ab && i /= snd ab) [1, 2, 3]

  print if L.length ans > 1 then -1 else head ans
```

### B - Piano 2

- [問題文](https://atcoder.jp/contests/abc355/tasks/abc355_b)
- [自分の回答](https://atcoder.jp/contests/abc355/submissions/53879451)

2つの配列AとBを受け取って結合してソートし、Aの値が2つ以上連結するかを問う問題です。

結合してソートした後も値がAかBかを判定できるように、`zip`を使ってタプルの配列にします。(今回はAを1として、Bを2としました。)
結合後に元の配列でソートし、Aの値(つまり1)が2つ以上連続するなら`Yes`を出力するようにします。

```haskell
main :: IO ()
main = do
  [n, m] <- readInputInts
  an <- zip (replicate n 1) <$> readInputInts
  bm <- zip (replicate m 2) <$> readInputInts

  let abn = L.map fst $ L.sortOn snd $ an ++ bm
  putStrLn if L.any (\lst -> head lst == 1 && length lst >= 2) $ L.group abn then "Yes" else "No"
```

ちなみに、「Aの値が2つ以上連続することを判定する」条件を見逃して1ペナ、さらにtypoに気づかず4ペナするという謎なことをしてしまいました…

### C - Bingo 2

- [問題文](https://atcoder.jp/contests/abc355/tasks/abc355_c)
- [自分の回答(upsolved)](https://atcoder.jp/contests/abc355/submissions/53949121)

`n x n`マスのビンゴを何回目に揃えたか？を問う問題です。
ビンゴが揃ったかを判定するために、行のリスト、列のリスト、斜めの変数2つを用意します。入力から値をうけとったら、その値に対応する行、列、斜めをインクリメントします。そしていずれかの値がnになったら（つまり揃ったら）それが何番目の回数かを出力します。

また、ある値がどの行、列にあるかを取得できるように、あらかじめ`listArray`で座標を取得しておきます。　`listArray`便利ですね。

あとは、事前に変数を用意しておき、都度更新する必要があるので、`IOUArray`や`IORef`を使い状態として扱えるようにします。
Haskellのような純粋関数型言語だとこの辺は慣れがいるなーという感じです。　

(ちなみにこの回答はほぼ[この回答](https://atcoder.jp/contests/abc355/submissions/53906431)のパクリです… )

```haskell
main :: IO ()
main = do
  [n, t] <- readInputInts
  ats <- zip [1 :: Int ..] <$> readInputInts

  let coord = listArray @Array (1, n * n) $ range ((1, 1), (n, n))

  cols <- newArray @IOUArray (1, n) (0 :: Int)
  rows <- newArray @IOUArray (1, n) (0 :: Int)

  diag1 <- newIORef (0 :: Int)
  diag2 <- newIORef (0 :: Int)

  for_ ats $ \(m, a) -> do
    let (i, j) = coord ! a

    modifyArray cols i (+ 1)
    modifyArray rows j (+ 1)

    when (i == j) $ modifyIORef' diag1 (+ 1)
    when (i + j - 1 == n) $ modifyIORef' diag2 (+ 1)

    c <- readArray cols i
    r <- readArray rows j
    d1 <- readIORef diag1
    d2 <- readIORef diag2

    when (n `elem` [c, r, d1, d2]) $ do
      print m
      exitSuccess

  print (-1 :: Int)

readInputInts :: IO [Int]
readInputInts = L.unfoldr (BC.readInt . BC.dropWhile C.isSpace) <$> BC.getLine

modifyArray :: (MArray a t m, Ix i) => a i t -> i -> (t -> t) -> m ()
modifyArray arr idx f = do
  v <- readArray arr idx
  writeArray arr idx $ f v
```
## 全体を振り返って

5月病ひどくてサボってましたが、またがんばります！

## おまけ

Rustの回答はこちら。　

- [A - Who Ate the Cake?](https://atcoder.jp/contests/abc355/submissions/54011527)
- [B - Piano 2](https://atcoder.jp/contests/abc355/submissions/54034359)
- [C - Bingo 2](https://atcoder.jp/contests/abc355/submissions/54056316)

ほぼHaskellを置き換えただけですが、C問題は`listArray`が使えないので

```rust
let coord = (0..n).flat_map(|i| iter::repeat(i).zip(0..n)).collect_vec();
```

で置き換えました。