Programming Contest - Snuke Festival
It's a good idea to profile your code (which is easy if you use stack – instead of stack build, just type stack build --profile, and run your program with the options +RTS -p) to find out exactly where the bottle-necks are. See the GHC profiling guide for more information.

If you do that, you'll find that a significant amount of your program's time is spent splitting up strings into words, and parsing them into Ints. Remember that a Haskell string is a linked list of characters, and thus not particularly efficient – I found that using the Text type from the text package results in the revised program taking only 40% of the time of your version. (Contrary to the other comment here, the binary search you've implemented seems fairly efficient, that's not where the slow-down is.)

Instead of getLine from the standard Prelude, use the version of getLine from Data.Text; instead of parsing a line of text using read . word, I'd suggest something like the following:

import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Read as T
import Data.Text (Text)

-- ...

forceEither :: Either a b -&gt; b
forceEither (Right r) = r 

parseLine :: Text -&gt; [Int]
parseLine txt =
  map (fst . forceEither . T.decimal) $ T.splitOn (T.pack " ") txt


(Possibly a hand-coded loop might be even faster than T.splitOn, but I didn't check that.)

I'd also suggest splitting out the parsing of input from the actual solving of the problem - no advantage is gained by putting everything into main. I'd further suggest that writing sum makes your intent clearer than foldl (+) 0; and that you use Vectors instead of Arrays, since this will (a) get rid of extra bits of cruft in the code and (b) allow you to use the vector-algorithms package, which already contains a binary search function. It's usually far better to use someone else's de-bugged search routine than write your own. However, if you are submitting for an online competition, that package may not be available. Nevertheless, it provides useful inspiration on how the search may be sped up.

This gives code along the following lines:

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}

import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Read as T
import Data.Text (Text)
import qualified Data.List as L

import qualified Data.Vector.Unboxed as V
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed.Mutable as VMut

import Control.Monad  ( replicateM )

import System.IO.Unsafe
import Data.Bits (shiftR)

-- adapted from "vector-algorithms" package:

{-# INLINE binarySearchPBounds #-}
binarySearchPBounds p vec = loop
 where
 loop !l !u
   | u &lt;= l    = return l
   | otherwise = VMut.unsafeRead vec k &gt;&gt;= \e -&gt; if p e then loop l k else loop (k+1) u
  where k = (u + l) `shiftR` 1

{-# INLINE binarySearchL #-}
binarySearchL vec e = binarySearchPBounds (&gt;= e) vec 0 (VMut.length vec)

{-# INLINE binarySearchR #-}
binarySearchR vec e = binarySearchPBounds (&gt; e) vec 0 (VMut.length vec)



forceEither :: Either a b -&gt; b
forceEither (Right r) = r 

parseLine :: Text -&gt; [Int]
parseLine txt =
  map (fst . forceEither . T.decimal) $ T.splitOn (T.pack " ") txt

bisectLeft :: Int -&gt; Vector Int -&gt; Int
bisectLeft n xs = unsafePerformIO $ do 
  xs' &lt;- V.unsafeThaw xs
  binarySearchL xs' n

bisectRight :: Int -&gt; Vector Int -&gt; Int
bisectRight n xs = unsafePerformIO $ do 
  xs' &lt;- V.unsafeThaw xs
  binarySearchR xs' n

getInput :: IO [Text]  
getInput = do
  res@[n, as, bs, cs] &lt;- replicateM 4 T.getLine
  return res

sortedVec :: t -&gt; Text -&gt; Vector Int
sortedVec n txt = 
  V.fromList $ L.sort $ parseLine txt


parseProblemInput
  :: [Text] -&gt; (Int, Vector Int, [Int], Vector Int)
parseProblemInput [nStr, asStr, bsStr, csStr] = 
  let [n] = parseLine nStr
      as =  sortedVec n asStr
      bs =  parseLine  bsStr
      cs = sortedVec n csStr
  in (n, as, bs, cs)

solve :: (Int, Vector Int, [Int], Vector Int) -&gt; Int
solve (n, as, bs, cs) = 
  sum $ map (\ b -&gt; bisectLeft b as * (n - bisectRight b cs)) bs


main = do
  ls &lt;- getInput 
  print $ solve $ parseProblemInput ls


This may not be as concise as your code, but should be much easier to follow and to modify - and importantly, for your purposes, it runs in less than half the time.

Other notes - the Unboxed versions of Vectors will normally be faster than the boxed versions, if you can use them; if you're submitting code for review, then I'd think a few more comments in your code wouldn't go astray. I hope that helps.