ABC 375
ABC 375 に参加しました。
| 問題 | A 問題 | B 問題 | C 問題 | D 問題 | E 問題 | F 問題 | 
|---|---|---|---|---|---|---|
| 提出 | AC | AC | - | AC | TLE | AC | 
| 予想 diff | 10 | 20 | 1,200 | 800 | 1,600 | 1,200 | 
| 実際 diff | 20 | 65 | 972 | 658 | 1,424 | 1,546 | 
A 問題
文字列 s を長さ 3 の窓で見て #.# の数を数えよ。 tails を思いつくと良かったです。
solve :: StateT BS.ByteString IO ()
solve = do
  !n <- int'
  !s <- BS.unpack <$> line'
  printBSB . length . filter (isPrefixOf "#.#") $ tails s
なんとなく suffix array っぽい?
B 問題
点から点への移動距離の和を小数型で求めよ。 zipWith 案件でした。
dist :: (Int, Int) -> (Int, Int) -> Double
dist (!x, !y) (!x', !y') = sqrt $ dx * dx + dy * dy
  where
    dx = intToDouble $ x - x'
    dy = intToDouble $ y - y'
solve :: StateT BS.ByteString IO ()
solve = do
  !n <- int'
  !xys <- (`U.snoc` (0, 0)) . U.cons (0, 0) <$> U.replicateM n ints2'
  let res = U.sum $ U.zipWith dist xys $ U.tail xys
  printBSB res
経験上、 \(10^{-6}\) までなら 64 bit 小数を使えば大丈夫! CS 的な知識も補填しないと……。
C 問題
グリッドの部分的な回転を繰り返したとき、最終的なグリッドの形を求めよ。回転の中心は常に一定のため、回転回数 mod 4 を考えます。
回転は以下:
rot90, rot180, rot270 :: Int -> (Int, Int) -> (Int, Int)
rot90 n (!y, !x) = (n - 1 - x, y)
rot180 n = rot90 n . rot90 n
rot270 n = rot90 n . rot90 n . rot90 n
グリッド生成を以下としました:
solve :: StateT BS.ByteString IO ()
solve = do
  !n <- int'
  !gr <- getGrid' n n
  let res = U.generate (n * n) $ \i ->
        let (!y, !x) = i `divMod` n
            d = (y `min` x `min` (n - 1 - y) `min` (n - 1 - x) + 1) `mod` 4
         in case d of
              0 -> gr @! (y, x)
              1 -> gr @! rot90 n (y, x)
              2 -> gr @! rot180 n (y, x)
              3 -> gr @! rot270 n (y, x)
              _ -> error "unreachable"
  printGrid $ IxVector (zero2 n n) res
D 問題
文字列 s の相異なる 3 点が回文となる場合の数を求めよ。左右端の文字種類毎に解いて足し合わせます。
累積和から区間和を取得する演算子を定義しました:
(++!) :: (HasCallStack) => U.Vector (Sum Int, Sum Int) -> (Int, Int) -> (Sum Int, Sum Int)
(++!) csum (!l, !r) = sub2 (csum G.! (r + 1)) (csum G.! l)
  where
    sub2 (!a, !b) (!c, !d) = (a - c, b - d)
紙の上で計算式を考え、ゴリゴリ解きます:
solve :: StateT BS.ByteString IO ()
solve = do
  !s <- U.map (subtract (ord 'A') . ord) . U.fromList . BS.unpack <$> line'
  let solve is
        | G.length is < 2 = 0
        | otherwise = U.sum $ U.imap f (U.init is)
        where
          n = G.length is
          input = U.map ((, Sum 1) . Sum) is
          csum = U.scanl' (<>) mempty input
          f i xl =
            let (Sum !sumR, Sum nr) = csum ++! (i + 1, n - 1)
             in sumR - (xl * nr) - nr
  let iss = V.generate 26 $ \i -> U.elemIndices i s
  printBSB $ G.sum $ G.map solve iss
E 問題
解説を読みました。適正難度 DP に負けたのは厳しい。。後ほど upsolve したいです。
F 問題
辺の追加クエリと最短経路クエリに答えよ。以下の制約が重要です。
- \(1 \le N \le 300\)
- 1 種類目 (辺の追加) クエリは 300 回以下である
辺の追加を \(O(N^2)\) 程度で処理できれば、全体で \(O(N^3)\) 程度の解答になります。
まず全点間距離を Floyd-Warshall で求めます。辺 (u, v, w) の追加の際は、各頂点 i, j の最短距離を経路 i -> u -> v -> j, および i -> v -> u -> j  の距離と比較して更新します。
実は何も考えなくても このスライドの P11 を書き写して解けました。 3 回連続、運に救われています。
Misc
BenQ Screenbar Pro
BenQ Screenbar Pro を買ってしまいました。手元が明るくなるのは良いのですが、モニタの周囲が暗いため、これはこれで目が疲れます。追加で間接照明を買うべきです。
これ一本で全部解決してくれると嬉しかったなと思います。そんな物は無い……!
Windows の使い道
以前 DTM 用途で Windows 機を購入ました。玄人志向の電源初期不良などを乗り越えましたが、その後ほぼ使っていません。
Android のエミュレータを入れて アークナイツ をインストールしました。うーんやるかなぁ
GNU Guix
Shell-based install に失敗しています。素直に GUI で入れるべきか……。