Is this special case of a scheduling problem solvable in linear time? Alice, a student, has a lot of homework over the next weeks.  Each item of homework takes her exactly one day.  Each item also has a deadline, and a negative impact on her grades (assume a real number, bonus points for only assuming comparability), if she misses the deadline.
Write a function that given a list of (deadline, grade impact) figures out a schedule for which homework to do on which day that minimizes the sum of bad impact on her grades.
All homework has to be done eventually, but if she misses a deadline for an item, it doesn't matter how late she turns it in.

In an alternative formulation:

ACME corp wants to supply water to customers.  They all live along one uphill street.  ACME has several wells distributed along the street.  Each well bears enough water for one customer.  Customers bid different amounts of money to be supplied.  The water only flows downhill.  Maximize the revenue by choosing which customers to supply.

We can sort the deadlines using bucket sort (or just assume we have already sorted by deadline).
We can solve the problem easily with a greedy algorithm, if we sort by descending grade impact first.  That solution will be no better than O(n log n).
Inspired by the Median of Medians and randomized linear minimum spanning tree algorithms, I suspect that we can solve my simple scheduling / flow problem in (randomized?) linear time as well.
I am looking for:

a (potentially randomized) linear time algorithm
or alternatively an argument that linear time is not possible

As a stepping stone:

I have already proven that just knowing which items can be done before their deadline, is enough to reconstruct the complete schedule in linear time.  (That insight is underlying the second formulation where I am only asking about certificate.)
A simple (integral!) linear program can model this problem.
Using duality of this program, one can check a candidate proposed solution in linear time for optimality, if one is also given the solution to the dual program.  (Both solutions can be represented in a linear number of bits.)

Ideally, I want to solve this problem in a model that only uses comparison between grade impacts, and does not assume numbers there.
I have two approaches to this problem---one based on treaps using deadline and impact, the other QuickSelect-like based on choosing random pivot elements and partitioning the items by impact.  Both have worst cases that force O(n log n) or worse performance, but I haven't been able to construct a simple special case that degrades the performance of both.
A few things I found out so far.

We can reduce ourselves to solving the following related problem:

newtype Slot = Slot Int
newtype Schedule a = Schedule [(Slot, [a])]

findSchedule :: Ord a =&gt; Schedule a -&gt; Schedule (a, Bool)


I.e. give the input data already sorted by deadline, but allow an arbitrary non-negative number of tasks to be done on each day.  Give the output by just marking the elements on whether they can be scheduled in time, or not.

The following function can check whether a schedule given in this format is feasible, ie whether all items still in the schedule can be scheduled before their deadlines:

leftOverItems :: Schedule a -&gt; [Int]
leftOverItems (Schedule sch) = scanr op 0 sch where
  op (Slot s, items) itemsCarried = max 0 (length items - s + itemsCarried)

feasible schedule = head (leftOverItems schedule) == 0


If we have a proposed candidate solution, and all items left out, we can check in linear time whether the candidate is optimal, or whether there are any items in the left-out set that would improve the solution.  We call these light items, in analogy to the terminology in Minimum Spanning Tree algorithm

carry1 :: Ord a =&gt; Schedule a -&gt; [Bound a]
carry1 (Schedule sch) = map (maybe Top Val . listToMaybe) . scanr op [] $ sch where
  op (Slot s, items) acc = remNonMinN s (foldr insertMin acc items)

-- We only care about the number of items, and the minimum item.
-- insertMin inserts an item into a list, keeping the smallest item at the front.
insertMin :: Ord a =&gt; a -&gt; [a] -&gt; [a]
insertMin a [] = [a]
insertMin a (b:bs) = min a b : max a b : bs

-- remNonMin removes an item from the list,
-- only picking the minimum at the front, if it's the only element.
remNonMin :: [a] -&gt; [a]
remNonMin [] = []
remNonMin [x] = []
remNonMin (x:y:xs) = x : xs

remNonMinN :: Int -&gt; [a] -&gt; [a]
remNonMinN n l = iterate remNonMin l !! n

data Bound a = Bot | Val a | Top
  deriving (Eq, Ord, Show, Functor)

-- The curve of minimum reward needed for each deadline to make the cut:
curve :: Ord a =&gt; Schedule a -&gt; [Bound a]
curve = zipWith min &lt;$&gt; runMin &lt;*&gt; carry1

-- Same curve extended to infinity (in case the Schedules have a different length)
curve' :: Ord a =&gt; Schedule a -&gt; [Bound a]
curve' = ((++) &lt;*&gt; repeat . last) . curve

-- running minimum of items on left:
runMin :: Ord a =&gt; Schedule a -&gt; [Bound a]
runMin = scanl1 min . map minWithBound . items . fmap Val

minWithBound :: Ord a =&gt; [Bound a] -&gt; Bound a
minWithBound = minimum . (Top:)

-- The pay-off for our efforts, this function uses
-- the candidate solution to classify the left-out items
-- into whether they are definitely _not_ in
-- the optimal schedule (heavy items), or might be in it (light items).
heavyLight :: Ord a =&gt; Schedule a -&gt; Schedule a -&gt; ([[a]],[[a]])
heavyLight candidate leftOut =
    unzip . zipWith light1 (curve' candidate) . items $ leftOut
  where
    light1 pivot = partition (\item -&gt; pivot &lt; Val item)


heavyLight not only checks a proposed schedules for optimality, it also gives you a list of items that can improve a non-optimal schedule.