AtCoder Beginner Contest 386 振り返り

ABC386の振り返りです。気づけば久しぶりの参加でした。
眠気がひどくて気づけば座ったまま寝てるレベルだったので、今回はUnratedの参加です。

## 結果

ABCの3完でした。

Unratedなのでratingの変動はありません。

![スクリーンショット 2024-12-29 15.07.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167729/1c322b8b-5675-f906-bf04-d2996d45f2ab.png)

もう少し速く解ける様になりたいな,,

## ふりかえり

### A問題

- 問題
  - https://atcoder.jp/contests/abc386/tasks/abc386_a
- 回答
  - https://atcoder.jp/contests/abc386/submissions/me?f.Task=abc386_a&f.LanguageName=&f.Status=&f.User=

sortして、数字でgroupingして、それぞれの長さを出力します。
最後にもう一回sortして、`[1, 3]`か`[2, 2]`のどちらかであればOKです。

最初にsortをするのを忘れて1ペナになりました。

```haskell
main :: IO ()
main = do
  abcd <- sort <$> getInts

  let p = sort $ map length $ group abcd

  putStrLn if p == [1, 3] || p == [2, 2] then "Yes" else "No"
```

### B問題

- 問題
  - https://atcoder.jp/contests/abc386/tasks/abc386_b
- 回答
  - https://atcoder.jp/contests/abc386/submissions/me?f.Task=abc386_b&f.LanguageName=&f.Status=&f.User=

`00`にマッチするとまるごと次にすすめ、それ以外だと一つづつ次にすすめます。

Haskellのパターンマッチを活用して、`('0':'0':t)`のようにマッチさせてときました。

```haskell
solve :: String -> Int
solve s = go s 0
  where
    go [] cnt = cnt
    go ('0' : '0' : st) cnt = go st (succ cnt)
    go (_ : st) cnt = go st (succ cnt)
    go _ _ = error "invalid parameter"
```

### C問題

- 問題
  - https://atcoder.jp/contests/abc386/tasks/abc386_c
- 回答
  - https://atcoder.jp/contests/abc386/submissions/me?f.Task=abc386_c&f.LanguageName=&f.Status=&f.User=

問題文の条件から、文字列の長さは高々1つしか変わりません。よって、条件を整理すると

1. SがTより一文字多い場合
2. TがSより一文字多い場合
3. SとTが同じ長さの場合

の3つに分けられます。
さらに、1.と2.は同じ解き方で解けるので、実質的には

1. 片方がもう片方より一文字多い場合
2. 両方が同じ長さの場合

とできます。

1. の場合は、再帰を利用して

```haskell
f1 :: String -> String -> Int
f1 s1 s2 = go s1 s2 0
  where
    go s1@(h1 : t1) s2@(h2 : t2) cnt = if h1 == h2 then go t1 t2 cnt else go t1 s2 cnt + 1
    go _ _ cnt = cnt
```

2.の場合は、`foldl'`を使って

```haskell
f2 :: String -> String -> Int
f2 s1 s2 =
  snd $
    foldl'
      ( \(h : t, cnt) c ->
          if h /= c
            then (t, cnt + 1)
            else (t, cnt)
      )
      (s2, 0)
      s1
```

でとけました。

最初は1.も2.と同じ様に`foldl'`で解こうとして

```haskell
f1 :: String -> String -> Int
f1 s1 s2 =
  snd $
    foldl'
      ( \(s@(h : t), cnt) c ->
          if h /= c
            then (s, cnt + 1)
            else (t, cnt)
      )
      (s2, 0)
      s1
```

としたのですが、これだと
例えばSが`"abc"`, Tが`"ab"`となった時に

Sが`'c'`の時に、Tの方に比較できる文字がないためエラーになってしまいます。(SとTが逆でも同様です。)

色々試行錯誤してmaybeで包むなども考えましたが、時間がないので再帰でときました。（結果的に3ペナだしました)

最終的なコードは以下の通りになりました。

```haskell
main :: IO ()
main = do
  _ <- getLine
  s <- getLine
  t <- getLine

  putStrLn $ if solve s t <= 1 then "Yes" else "No"

solve :: [Char] -> [Char] -> Int
solve s t
  | lenS == lenT = f2 s t
  | lenS == lenT - 1 = f1 t s
  | lenS == lenT + 1 = f1 s t
  | otherwise = maxBound
  where
    lenS = length s
    lenT = length t

f1 :: String -> String -> Int
f1 s1 s2 = go s1 s2 0
  where
    go s1@(h1 : t1) s2@(h2 : t2) cnt = if h1 == h2 then go t1 t2 cnt else go t1 s2 cnt + 1
    go _ _ cnt = cnt

f2 :: String -> String -> Int
f2 s1 s2 =
  snd $
    foldl'
      ( \(h : t, cnt) c ->
          if h /= c
            then (t, cnt + 1)
            else (t, cnt)
      )
      (s2, 0)
      s1
```

## 全体を振り返って

なんとか3完できましたが、もっと速くとけないとなーと思いました。
来年に向けてもっと精進していきたいです。