Open5

競プロにHaskellで

bunnyhopper_isolatedbunnyhopper_isolated

001 - Yokan Party(★4)
解説のまま二分探索

import Control.Monad
import qualified Data.ByteString.Char8 as BS
import Data.Maybe
    

split_over :: Int -> [Int] -> [Int] 
split_over x (a1:a2:as) =
    if (a2 - a1) >= x
        then (a2 - a1) : (split_over x (a2:as))
        else split_over x (a1:as)
split_over _ _ = []
        

search :: Int -> [Int] -> Int -> Int -> Int
search k ass l r
    | (r - l) <= 1 = l
    | otherwise = search k ass nl nr
                    where mid = (l + r) `div` 2
                          hit = (k+1) <= (length (split_over mid ass))
                          nr = if hit then r else mid
                          nl = if hit then mid else l
                          

main = do
    [n, l] <- myGetIntMul    
    k <- myGetInt
    as <- myGetIntMul

    let r = search k ([0] ++ as ++ [l]) (-1) (l+1)

    print r

myGetInt :: IO Int
myGetInt = fst . fromJust . BS.readInt <$> BS.getLine

myGetIntMul :: IO [Int]
myGetIntMul = map (fst . fromJust . BS.readInt) . BS.words <$> BS.getLine
    
myGetStr = BS.getLine

myGetIntMulN :: IO [[Int]] 
myGetIntMulN = do
    n <- myGetInt
    l <- replicateM n myGetIntMul
    return l

bunnyhopper_isolatedbunnyhopper_isolated

002 - Encyclopedia of Parentheses(★3)
概ね解説と一緒。結果ソートが不要だったので"instance Ord Pars"は使用していない。

import Control.Monad
import qualified Data.ByteString.Char8 as BS
import Data.Maybe

data Pars = Start | End deriving(Show, Eq)

instance Ord Pars where
    compare Start Start = EQ
    compare Start End   = LT
    compare End Start   = GT
    compare End End     = EQ

cartesianProductN :: Int -> [a] -> [[a]]
cartesianProductN n xs = sequence $ replicate n xs

checkStack :: Int -> [Pars] -> Bool
checkStack 0 [] = True
checkStack _ [] = False
checkStack c (x:xs)
    | c < 0 = False
    | x == Start = checkStack (c+1) xs 
    | x == End = checkStack (c-1) xs 
    

validate :: [Pars] -> Bool
validate xs = checkStack 0 xs

pars2Char :: Pars -> Char
pars2Char Start = '('
pars2Char End   = ')'

printVal :: Int -> IO ()
printVal n = do
    let l = cartesianProductN n [Start, End]    
    let good_l = filter validate l
    let good_ls = map (map pars2Char) good_l
    mapM_ putStrLn good_ls


main = do
    n <- myGetInt

    if n `mod` 2 == 0 
        then printVal n
        else putStr "" 

myGetInt :: IO Int
myGetInt = fst . fromJust . BS.readInt <$> BS.getLine

bunnyhopper_isolatedbunnyhopper_isolated

003 - Longest Circular Road(★4)

苦戦中。解説は理解できるが、実装方法の整理がついていない。
以下はライブラリを活用している。
https://atcoder.jp/contests/typical90/submissions/46157895

上記はまずグラフを構成し、そこからdfs(Data.Graph)で任意のノードからスパニングツリーを作成している。木にしてしまえば単純な再帰で最も深いノードを見つけることができ、それはグラフ上での最も遠いノードとなる。
解説の通りこれを2回行うことでグラフの直径が分かる。
ということらしい。

bunnyhopper_isolatedbunnyhopper_isolated

DP(動的計画法)の勉強
ここを参考として以下の様に書けた。

type Weight = Int
type Value = Int

dp' :: Int -> [Value] -> (Weight, Value) -> [Value]
dp' w_lim befVals (w, v) = map (nextVals) [0..w_lim]
    where
        nextVals wi = if wi < w
                        then befW
                        else max befW $ (befVals !! (wi - w)) + v
            where befW = befVals !! wi

dp :: Int -> [(Weight, Value)] -> Int
dp w weiVals = (foldl (dp' w) (replicate (w+1) 0) weiVals) !! w

main = do
    let w = 9
    let vals = [
                 (2, 3)
               , (1, 2)
               , (3, 6)
               , (2, 1)
               , (1, 3)
               , (5, 85)
               ] 

    let r = dp 9 vals
    print r
bunnyhopper_isolatedbunnyhopper_isolated

004 - Cross Sum(★2)
素直に書いてしまいTLEになった。
以下に記述されている様にVectorを使用することで解決できた。
https://booth.pm/ja/items/1577541

import Control.Monad
import qualified Data.ByteString.Char8 as BS
import Data.Maybe
-- import Data.Map
import Data.List (transpose)
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector as V

calcSumH as = map pickSum [0..((length (as!!0))-1)]
    where
        pickSum t = foldl (\acc a -> acc + (a !! t)) 0 as

main = do
    [h, w] <- myGetIntMul    
    as <- replicateM h myGetIntMul
    let asV = V.fromList $ map VU.fromList as

    let sumW = VU.fromList $ map sum as
    let sumH = VU.fromList . map sum $ transpose as

    let r = map (\hi -> map (\wi -> (sumWH hi) + (sumHW wi) - (eVal hi wi)) w_range) h_range
                where
                    w_range = [0..(w-1)]
                    h_range = [0..(h-1)]
                    sumWH hi = sumW VU.! hi
                    sumHW wi = sumH VU.! wi
                    eVal hi wi = asV V.! hi VU.! wi

    mapM_ (putStrLn . unwords . map show) r

myGetInt :: IO Int
myGetInt = fst . fromJust . BS.readInt <$> BS.getLine

myGetIntMul :: IO [Int]
myGetIntMul = map (fst . fromJust . BS.readInt) . BS.words <$> BS.getLine
    
myGetStr = BS.getLine

myGetIntMulN :: IO [[Int]] 
myGetIntMulN = do
    n <- myGetInt
    l <- replicateM n myGetIntMul
    return l