I have a problem to solve. Details of it basically irrelevant & I have two valid solutions for it: in python and Haskell.
Python code:
import heapq
_, volume, *ppl = map(int, open("input.txt").read().split())
ppl = [-x for x in ppl]
heapq.heapify(ppl)
for i in range(volume):
current = (- heapq.heappop(ppl)) // 10
heapq.heappush(ppl, -current)
print(sum(-x for x in ppl), file=open("output.txt", 'w'))
Haskell code:
import Data.List hiding (insert, singleton)
type Rank = Int
data Heap a = Tip | Node Rank Int (Heap Int) (Heap Int)
rank Tip = 0
rank (Node r _ _ _) = r
fromList :: [Int] -> Heap Int
fromList [] = Tip
fromList (x:xs) = foldl' (flip insert) (singleton x) xs
makeHeap :: Int -> Heap Int -> Heap Int -> Heap Int
makeHeap x a b = if rank a >= rank b then Node (rank b + 1) x a b
else Node (rank a + 1) x b a
empty :: Heap a
empty = Tip
singleton :: Int -> Heap Int
singleton x = Node 1 x Tip Tip
insert :: Int -> Heap Int -> Heap Int
insert x = merge (singleton x)
merge :: Heap Int -> Heap Int -> Heap Int
merge l Tip = l
merge Tip r = r
merge h1@(Node _ x l1 r1) h2@(Node _ y l2 r2) =
if x > y then makeHeap x l1 (merge r1 h2)
else makeHeap y l2 (merge h1 r2)
-- | O(1).
peek :: Heap Int -> Int
peek Tip = 0
peek (Node _ x _ _) = x
-- | O(1), but evaluating the second element of the tuple has same complexity
-- of `merge`.
extract :: Heap Int -> (Int, Heap Int)
extract (Node _ x a b) = (x, merge a b)
toSum :: Heap Int -> Int
toSum Tip = 0
toSum (Node _ x a b) = x + toSum a + toSum b
solve :: Int -> Heap Int -> Int
solve 0 heap = toSum heap
solve _ (Node _ 0 _ _) = 0
solve sips ppl = solve (sips - 1) (insert (val `div` 10) h)
where (val, h) = extract ppl
main :: IO()
main = do
line <- readFile "input.txt"
let _:volume:ppl = map(read :: String -> Int) $ words line
let heap = fromList ppl
writeFile "output.txt" $ show $ solve volume heap
The question borrowed is in the following slice of the results table:
| N of test | Verdict | Time (sec) python | Time (sec) Haskell |
|---|---|---|---|
| 19 | OK | 0.0312 | 0.0156 |
| 20 | OK | 0.0624 | 0.172 |
| 21 | OK | 0.078 | 0.733 |
| 22 | OK | 0.234 | 1.34 |
| 23 | OK | 0.218 | 1.34 |
Tests itself is unavailable to me.
So... Seems like my Haskell code for some reason is significantly slower with high amount of values (~10^5). Could someone explain me why and how to fix it?
makeHeapandmergeare bothO(n). Have a look at en.wikipedia.org/wiki/Heap_(data_structure)#Implementation In Haskell, hackage.haskell.org/package/vec is the normal go-to lib if you need an array (which is not just a linked list).extractshould be O(lg n), and it's not obvious thatmergeis O(lg n) as it needs to be.