AtCoder Beginner Contest 359 振り返り

ABC359の振り返りです。今回は早めに振り返り。

## 結果

A,Bの2完でした。CもうちょっとでACできたのですが間に合わず、、

![スクリーンショット 2024-06-23 0.53.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/57f31d5d-bfc0-ef26-019b-5281908aeabb.png)

## 解説

### A問題

- [問題](https://atcoder.jp/contests/abc358/tasks/abc358_a)
- [回答](https://atcoder.jp/contests/abc359/submissions/54799419)

filterしてlengthをとります。

```haskell
main :: IO ()
main = do
  n <- readLn @Int
  ss <- replicateM n getLine

  print $ L.length $ L.filter (== "Takahashi") ss
```

### B問題

- [問題](https://atcoder.jp/contests/abc359/tasks/abc359_b)
- [回答](https://atcoder.jp/contests/abc359/submissions/54811552)

`dropWhile`と`takeWhile`を組み合わせて、長さが1の要素を畳み込みでカウントしました。

```haskell
main :: IO ()
main = do
  n <- readLn @Int
  an <- readInputInts

  print $
    L.foldl'
      ( \acc a ->
          if L.length (L.takeWhile (/= a) (tail $ L.dropWhile (/= a) an)) == 1
            then acc + 1
            else acc
      )
      0
      [1 .. n]
```

### C問題(upsolved)

- [問題](https://atcoder.jp/contests/abc359/tasks/abc359_c)
- [回答](https://atcoder.jp/contests/abc359/submissions/54849935)

キツかったです。問題を読み解いて絵を描きながら条件をこまかく分類していきました。
やったことは以下の通りです。

1. x座標が小さい方をスタート地点`(sx, sy)`として置き換える
2. 原点の座標のx+yが偶数ならxに1を追加する(タイルの右端に寄せる)
3. ゴールの座標のx+yが奇数ならxから1を引く(タイルの左端に寄せる)
4. 2つの座標の差分を取り、`yの差分>=xの差分`であれば、yをそのまま回答にする
5. yの方が小さければ、xをyの座標分移動させ、x軸方向のタイルの差分を取得する。これにyの差分を加えたものを回答にする。

ポイントは4と5です。
タイルの形状がx軸方向に2マスくっついているので、y座標が一つ移動すると、x座標もタイルを跨がず一つ移動することができます。
なので、`yの差分>=xの差分`であれば、タイルを跨らずにゴールまで移動することが可能です。
逆に、`yの差分<xの差分`であれば、y座標分の距離をx軸に沿って移動したあとに、`スタート地点とゴール地点のx座標のタイルを跨った数 + yの差分`で答えを求めることができます。

ちなみに、x座標同士のタイルの計算は、私は以下の計算で求めました。

```haskell
(tx - sx) - (tx - sx) `div` 2 
```

が、これはおそらく以下で求められると思われます。

```haskell
(tx - sx) `div` 2
```

ソースの全体を載せておきます。

```haskell
main :: IO ()
main = do
  [sx, sy] <- readInputInts
  [tx, ty] <- readInputInts

  let (sx', sy') = if sx > tx then (tx, ty) else (sx, sy)
  let (tx', ty') = if sx > tx then (sx, sy) else (tx, ty)

  let sx'' = if even (sx' + sy') then sx' + 1 else sx'
  let tx'' = if odd (tx' + ty') then tx' - 1 else tx'

  print $ calc (sx'', sy') (tx'', ty')

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

calc :: Integral a => (a, a) -> (a, a) -> a
calc (sx, sy) (tx, ty) =
  let xdiff = tx - sx
      ydiff = ty - sy
   in if xdiff <= abs ydiff
        then abs ydiff
        else
          let (sx', sy') = (sx + abs ydiff, sy + ydiff)
           in let sx'' = if even (sx' + sy') then sx' + 1 else sx'
               in (tx - sx'') - (tx - sx'') `div` 2 + abs ydiff
```

[公式の解答](https://atcoder.jp/contests/abc359/editorial/10278)をみると、もっと簡単に書けるようで、実際書き直すと以下の様になりました。
`mod`や`max`をうまく使い、不要な条件分岐を減らしています。

```haskell
main :: IO ()
main = do
  [sx, sy] <- map toInteger <$> readInputInts
  [tx, ty] <- map toInteger <$> readInputInts

  let sx' = sx - (sx + sy) `mod` 2
  let tx' = tx - (tx + ty) `mod` 2
  let (ttx, tty) = (abs (tx' - sx'), abs (ty - sy))

  print $ tty + max 0 (ttx - tty) `div` 2
```


## 全体を振り返って

個人的にC難しかったです、、問題見て焦りました。
typoが原因でACできなかったので、もうちょっとおちついて解くとよかったのかもしれません。

## おまけ Rustの回答

いつもの如くRustで解き直して見ました。
他の言語で書いてみると、ちょっと違った頭を使えて良いですね。

- [問題A](https://atcoder.jp/contests/abc359/submissions/54856239)
- [問題B](https://atcoder.jp/contests/abc359/submissions/54856510)
- [問題C](https://atcoder.jp/contests/abc359/submissions/54856754)