AtCoder Beginner Contest 330 振り返り
昨日の振り返りです!
結果
C問題でWAが解決できずに終わってしまいました
レーティングはちょっと上がったけど納得いかない
各問題の振り返り
A - Counting Passes
ある値以上の要素をカウントする問題。
filterしてlengthするだけです。
main :: IO ()
main = do
[_, l] <- readInputIntList
as <- readInputIntList
print $ length $ filter (>= l) as
B - Next
最初問題見た時「何これ?」なった問題です。(笑)
わかれば難しいことはなくて、入力値に対して絶対値が最も小さくなる値、つまり最も近い値を求める問題です。
$${A_i}$$ が $${L \le X \le R}$$の間にいる間は$${A_i}$$がそのまま回答になって、$${A_i \lt L}$$ の場合は $${L}$$ , $${A_i \gt R}$$ の場合は$${R}$$が回答になります。二分探索も考えましたが全探索で十分でした。
main :: IO ()
main = do
[_, l, r] <- readInputIntList
as <- V.fromList <$> readInputIntList
putStrLn $ unwords $ V.toList $ V.map show $ findClosest l r as
findClosest :: Int -> Int -> V.Vector Int -> V.Vector Int
findClosest l r = V.map go
where
go a
| a < l = l
| a > r = r
| otherwise = a
C - Minimize Abs 2
$${\vert x^2 + y^2 - D \vert}$$の最小値を求める問題。xを固定してyを二分探索で解けそうだなーと思ったんですが、何回やってもWAで終わってしまいました。。
main :: IO ()
main = do
d <- readInputInt
print $ findMinDiff d
findMinDiff :: Int -> Int
findMinDiff d = minimum [abs (x ^ 2 + y ^ 2 - d) | x <- [0 .. limit], let y = bSearch 0 limit (x ^ 2)]
where
limit = floor . sqrt $ fromIntegral d
bSearch l h x2
| h < l = h
| otherwise =
let mid = l + (h - l) `div` 2
midVal = mid ^ 2
in if midVal + x2 == d
then mid
else
if midVal + x2 < d
then bSearch (mid + 1) h x2
else bSearch l (mid - 1) x2
Xでnaoyaさんが平方数をあらかじめ生成して三分探索を使えば解けると言っていたので、この解法で解き直したところACになりました。
三分探索は凹凸型の関数の最小・最大値を求める時に使えるアルゴリズムで、今回のような$${\vert x^2 + y^2 - D \vert}$$の最小値を求めるケースに適用できます。(cyancyanさん教えていただきありがとうございました!)
実際に解いてみると実装は以下のようになります。
main :: IO ()
main = do
d <- readLn @Int
let xs = takeWhile (<= d) $ map (\i -> i * i) [0 ..]
n = length xs
ys = listArray @UArray (1, n) xs
f d x y = abs (x + y - d)
res = minimum $ concat [map (\i -> f d x (ys ! i)) (range result) | x <- xs, let result = trisect (1, n) (\i -> f d x (ys ! i))]
print res
trisect :: (Int, Int) -> (Int -> Int) -> (Int, Int)
trisect (l, r) f
| r - l <= 2 = (l, r)
| f m1 > f m2 = trisect (m1, r) f
| otherwise = trisect (l, m2) f
where
m1 = (l * 2 + r) `div` 3
m2 = (l + r * 2) `div` 3
これだとACになりました。
全体を振り返って
C問題解けると思ったんだけどできなかったなあ…
おまけ
今回、何のテストで落ちているかがわからなかったのが敗因の一つなので、次回からプロパティベーステストを使いたいと思っています。
プロパティベーステストとは超ざっくり説明すると「プロパティに沿ってテストデータを自動生成する単体テスト」のことを指します。
実践プロパティベーステストも買ったので、これを読んで勉強しながら次に備えたいと思います!
https://www.lambdanote.com/collections/proper-erlang-elixir/products/proper-ebook
この記事が気に入ったらサポートをしてみませんか?