Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

ABC113をHaskellで

0
Last updated at Posted at 2026-01-12

A - Discount Fare

問題 ABC113A

シグネチャを決める。

abc113a :: Int -- X
        -> Int -- Y
        -> Int -- 答え
abc113a x y = x + div y 2

B - Palace

問題 ABC113B

シグネチャを決める。

abc113b :: Int -- N
        -> Int -- T
        -> Int -- A
        -> [Int] -- Hi
        -> Int -- 答え

$|(T-x \times 0.006) - A|$ が最小となる $H_i$ を探す。
1000倍して
$|1000(T - A) - 6x|$ とすると整数演算できる。

結果

abc113b n t a hs = snd $ minimum
  [(abs (1000 * (t - a) - 6 * h), i) | (i, h) <- zip [1 ..] hs]

C - ID

問題 ABC113C

シグネチャを決める。横着する。

abc113c :: Int -- N
        -> Int -- M
        -> [[Int]]  -- Pi,Yi
        -> [String] -- 答え

まず県ごとに寄せる。
県の中で年でソートして番号$x$を確定させ、
これにより完成する認識番号を配列で集める。

結果

leading zero を付けるには、はみ出る桁に数を置いてから show してそれを除けばよい。

import Data.Array
import Data.List

abc113c :: Int-> Int -> [[Int]] -> [String]
abc113c n m pys = elems ans
  where
    prefs = accumArray (flip (:)) [] (1,n)
            [(p, (y,i)) | (i, p:y:_) <- zip [1 ..] pys]
    ans = array (1,m)
      [ (i, tail $ show $ pp + x)
      | (p, yis) <- assocs prefs
      , let pp = 1000000 * (1000000 + p)
      , (x, (y,i)) <- zip [1 ..] $ sort yis]

D - Number of Amidakuji

問題 ABC113D

シグネチャを決める。

abc113d :: Int -- W
        -> Int -- H
        -> Int -- K
        -> Int -- 答え
abc113d w h k = ...
  where
    w1 = pred w

考える

縦線$W$本のとき、ある高さに引く横線を引ける箇所は $W-1$ 箇所ある。
ただし規則1のため、線の引き方の場合の数は $2^{W-1}$ とはならない。
1のビットが連続しない2進数として列挙すると簡単。

import Data.Bits

    yokos = gen w1 :: [Int]
    gen w = [i | i <- [0 .. 2^w - 1], i .&. (i .<<. 1) == 0]

高さパラメータが $H$ のとき、横線を引ける高さが $H$ 箇所ある。
自分がこの高さにおいて $1 \leq P \leq W$ に来るような場合の数、を追跡するDPを行う。

各位置について、左隣に移る、下に進む、右隣に移る、ような横線の引き方の場合の数を数える。
(これは「配るDP」の言い方だが、同時に「左隣から移ってくる」という集めるDPのパラメータとしても解釈できる。)

import Data.Array

-- 縦線の番号0~W-1について、+1に移動するような横線の数は、そのビットが1のもの
    rights = elems $ accumArray (+) 0 (0,w1) [(i, 1) | y <- yokos, i <- [0 .. w1], testBit y i]
-- -1に移動するような横線の数は、一つ下のビットが1のもの
    lefts = elems $ accumArray (+) 0 (0,w1) [(i, 1) | y <- yokos, let y1 = y .<<. 1, i <- [0 .. w1], testBit y1 i]
-- 0に移動するようなパターンの数は、LでもRでもないもの
    num = length yokos
    mids = zipWith (\l r -> num - l - r) rights lefts

ここまで準備ができたら、$H$ 段のDPステップを実行して答えを求められる。

abc113d [h,w,k] = fin !! pred k
  where
    ini = 1 : replicate (pred w1) 0
    fin = iterate step ini !! h
    step cnt = map (reg . sum) $ transpose
      [ zipWith mul lefts  $ 0 : cnt
      , zipWith mul rights $ tail cnt
      , zipWith mul mids     cnt ]

公式解説

計算量 $O(HW2^W)$ と言っているのは、DPのステップごとに、横棒の配置全てを毎回全列挙して次の段を数えている?
ここで示した step は $O(W)$ なので全体は普通に $O(HW)$ で、フィボナッチ数がどう関係してくるのかわからない。???

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?