Open5
競プロにHaskellで
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
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
003 - Longest Circular Road(★4)
苦戦中。解説は理解できるが、実装方法の整理がついていない。
以下はライブラリを活用している。
上記はまずグラフを構成し、そこからdfs(Data.Graph)で任意のノードからスパニングツリーを作成している。木にしてしまえば単純な再帰で最も深いノードを見つけることができ、それはグラフ上での最も遠いノードとなる。
解説の通りこれを2回行うことでグラフの直径が分かる。
ということらしい。
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
004 - Cross Sum(★2)
素直に書いてしまいTLEになった。
以下に記述されている様にVectorを使用することで解決できた。
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