ABC 432
ABC 432 に参加しました。 D 問題で ac-library-hs を使用しました。
A 問題
数列を並び替え、最も大きな値を作成せよ。数列を降順ソートした後、連結して出力します:
solve :: StateT BS.ByteString IO ()
solve = do
!xs <- U.toList <$> intsU'
printBSB . concatMap show $ sortBy (comparing Down) xsB 問題
数列を並び替え、 0 以外から始まる最も小さな値を作成せよ。全探索が楽なようです:
solve = do
!xs <- sort . BS.unpack <$> line'
printBSB . fromJust . find ((/= '0') . head) $ permutations xsC 問題
難しめの問題です。問題文を省略します。
または () を合計 個取るとき、和 が取り得る値の集合は、 の区間を で移動した点の集まりです。この集合を とすると、 の共通集合の最大の値が必要です。
が空集合でないためには が必須です。この条件下では、積集合を により計算できます。
feat :: Int -> Int -> Int -> (Int, Int, Int)
feat a b n = (modX, minX, maxX)
where
d = b - a
maxX = b * n
minX = a * n
modX = maxX `mod` d
solve :: StateT BS.ByteString IO ()
solve = do
(!n, !a, !b)<- ints3'
!xs <- intsU'
let (mods, mins, maxes) = U.unzip3 $ U.map (feat a b) xs
let b1 = U.all (== U.head mods) mods
let l = U.maximum mins
let r = U.minimum maxes
let b2 = l <= r
if b1 && b2
then do
let d = b - a
printBSB . U.sum $ U.map ((`div` d) . (r -)) mins
else do
printBSB "-1"D 問題
長方形が配置された空間にねじれを加えていく問題です。千切れた長方形もまとめてねじって行き、最終的な連結成分のサイズを回答します。
長方形毎に位置とサイズを追跡し、千切れた部分は後から連結判定することで、 で解けそうです。
長方形の隣接判定がこちら:
isAdj :: (Int, Int, Int, Int) -> (Int, Int, Int, Int) -> Bool
isAdj r1@(!y, !x, !h, !w) r2@(!y', !x', !h', !w')
| x + w == x' || x' + w' == x =
let yMin = max y y'
yMax = min (y + h - 1) (y' + h' - 1)
in yMin <= yMax
| y + h == y' || y' + h' == y =
let xMin = max x x'
xMax = min (x + w - 1) (x' + w' - 1)
in xMin <= xMax
| otherwise = False長方形の追跡と、連結成分の個数確認が以下です。上下と左右のねじれでコードがダブっているとはいえ、重いです:
-- (2^n)^2 < 10^9. Neraly safe.
solve :: StateT BS.ByteString IO ()
solve = do
(!n, !w0, !h0) <- ints3'
!cds <- U.replicateM n ((,,) <$> char' <*> int' <*> int')
-- track rects
let res1 = U.foldl' step s0 cds
where
s0 = U.singleton (0, 0, h0, w0)
step rects ('X', !atX, !dy) = U.concatMap f rects
where
f (!y, !x, !h, !w)
| x + w <= atX = U.singleton (y - dy, x, h, w)
| x >= atX = U.singleton (y + dy, x, h, w)
| otherwise = U.fromListN 2 [b1, b2]
where
b1 = (y - dy, x, h, atX - x)
b2 = (y + dy, atX, h, x + w - atX)
step rects ('Y', !atY, !dx) = U.concatMap g rects
where
g (!y, !x, !h, !w)
| y + h <= atY = U.singleton (y, x - dx, h, w)
| y >= atY = U.singleton (y, x + dx, h, w)
| otherwise = U.fromListN 2 [b1, b2]
where
b1 = (y, x - dx, atY - y, w)
b2 = (atY, x + dx, y + h - atY, w)
step _ _ = error "unreachable"
-- merge and return counts
let res = U.filter (/= 0) $ U.create $ do
let len = G.length res1
groups <- Dsu.new len
counts <- U.unsafeThaw $ U.map (\(!_, !_, !h, !w) -> h * w) res1
U.iforM_ res1 $ \i r -> do
let rects = U.take i res1
U.iforM_ rects $ \i' r' -> do
when (isAdj r r') $ do
-- change the belonging group
r1 <- Dsu.leader groups i
r2 <- Dsu.leader groups i'
r <- Dsu.merge groups i i'
-- move the count to the group
a1 <- GM.exchange counts r1 0
a2 <- GM.exchange counts r2 0
GM.write counts r $ a1 + a2
pure counts
printBSB $ U.length res
printBSB . unwordsBSB $ U.modify VAI.sort resなお 解説 によると、長方形の区間は のとき最大で になるそうです。 ではないのですね……。安易な計算量解析で結論を出してはいけないことが分かります。形上せよ!
E 問題
Clamped range sum 的な問題です。僕は本番で解けませんでしたが、頻度分布を持てば解けるようです。確かに……。
- エッジケースとして、 clamp のクエリが である場合があります。
感想
D のような PAST 的、実務的な泥臭い問題が好きです。
Misc
音楽
Bliss of Flesh の 新盤 が出ました。最高の出来とは言えないのですが、やはり曲調が僕の中では No. 1 です。
これが最後のアルバムとなるのでしょうか。誰も歳には勝てませんね。