[Haskell-cafe] Open Kattis Problem Srednji: Hints to improve my algorithm

Dominik Bollmann dominikbollmann at gmail.com
Thu Sep 24 19:15:19 UTC 2020


Thank you for the input and hints, Viktor and Brent. I appreciate it!
I'll try to come up with a better algorithm.

Thanks!

Dominik


Brent Yorgey <byorgey at gmail.com> writes:

> Viktor is right.  Here's a small hint towards one way of solving it: start
> by replacing every number smaller than B by -1, and every number larger
> than B by 1 (and B itself by 0).
>
> -Brent
>
> On Wed, Sep 23, 2020 at 2:17 AM Dominik Bollmann <dominikbollmann at gmail.com>
> wrote:
>
>>
>> Hi Haskell-Cafe,
>>
>> I've been trying to solve the Open Kattis Problem called Srednji
>> recently, unfortunately without success.
>>
>> Given a sequence A and a number B within that sequence this problem asks
>> to find all odd sub-sequences of A that, when sorted, have B as their
>> median in the middle. That is, from A we may remove some prefix and/or
>> suffix and if the resulting sub-sequence -- when sorted -- contains B in
>> the middle, then this sub-sequence is a solution. The problem asks to
>> find the number of all solutions. Check out
>> https://open.kattis.com/problems/srednji for the details.
>>
>> My Haskell solution below tries to find the number of odd sub-sequences
>> by first locating the median and then repeatedly moving left and right
>> from that median to find larger and larger sub-sequence candidates. Each
>> found candidate is checked to have B in the middle when sorted in order
>> to become a solution. Moreover, I also extend each such candidate
>> further to the left (and to the right, respectively) to determine
>> whether these leftward or rightward extensions are solutions, too.
>>
>> I think with this approach I systematically enumerate all solutions.
>> Unfortunately, though, this approach is too slow and times out on the
>> 11th hidden test cases.
>>
>> I'd therefore be thankful for hints about different approaches to
>> solving this problem more efficiently.
>>
>>
>> Thanks!
>>
>> Dominik.
>>
>> ====================================================================
>>
>> My current, slow Haskell code is this:
>>
>> import Data.Maybe
>> import Data.Sequence (Seq, (<|), (|>))
>> import qualified Data.Sequence as Seq
>> import qualified Data.Vector.Unboxed as Vec
>>
>> data SubSeq = SubSeq
>>   { getBalance :: {-# UNPACK #-} !Int
>>   , getSubSeq  :: Seq Int
>>   , from       :: {-# UNPACK #-} !Int
>>   , to         :: {-# UNPACK #-} !Int
>>   }
>>
>> balancedSubSeqs :: [Int] -> Int -> [SubSeq]
>> balancedSubSeqs seq med = do
>>   candidate <- leftRight [val0]
>>   let lefts  = leftLeft candidate []
>>       rights = rightRight candidate []
>>   candidate ?: lefts ++ rights
>>   where
>>     medidx = fromJust (Vec.findIndex (== med) arr)
>>     val0   = SubSeq 0 (Seq.singleton med) medidx medidx
>>     arr    = Vec.fromList seq
>>
>>     leftRight cands@(SubSeq balance seq i j : _)
>>       | i-1 < 0 || j+1 >= Vec.length arr = cands
>>       | otherwise =
>>         let v1       = arr Vec.! (i-1)
>>             v2       = arr Vec.! (j+1)
>>             balance' = newBalance balance v1 v2
>>             seq'     = (v1 <| seq) |> v2
>>         in leftRight (SubSeq balance' seq' (i-1) (j+1) : cands)
>>
>>     leftLeft cand@(SubSeq balance seq i j) sols
>>       | i-2 < 0   = sols
>>       | otherwise =
>>         let v1 = arr Vec.! (i-2)
>>             v2 = arr Vec.! (i-1)
>>             balance' = newBalance balance v1 v2
>>             seq'     = v1 <| v2 <| seq
>>             newCand  = SubSeq balance' seq' (i-2) j
>>         in leftLeft newCand (newCand ?: sols)
>>
>>     rightRight cand@(SubSeq balance seq i j) sols
>>       | j+2 >= Vec.length arr = sols
>>       | otherwise =
>>         let v1 = arr Vec.! (j+1)
>>             v2 = arr Vec.! (j+2)
>>             balance' = newBalance balance v1 v2
>>             seq'     = seq |> v1 |> v2
>>             newCand  = SubSeq balance' seq' i (j+2)
>>         in rightRight newCand (newCand ?: sols)
>>
>>     newBalance old n1 n2
>>       | n1 < med, n2 < med = old - 2
>>       | n1 > med, n2 > med = old + 2
>>       | otherwise          = old
>>
>> infixr 5 ?:
>> --(?:) :: SubSeq -> [SubSeq] -> [SubSeq]
>> x@(SubSeq b _ _ _) ?: xs
>>   | b == 0    = x : xs
>>   | otherwise = xs
>>
>> main :: IO ()
>> main = do
>>   [len, median] <- fmap read . words <$> getLine
>>   seq <- fmap read . words <$> getLine
>>   let solutions = balancedSubSeqs seq median
>>   print (length solutions)
>> _______________________________________________
>> Haskell-Cafe mailing list
>> To (un)subscribe, modify options or view archives go to:
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> Only members subscribed via the mailman list are allowed to post.


More information about the Haskell-Cafe mailing list