You’re building the Tasker app for a logistics marketplace with millions of monthly active contractors. Taskers often lose connectivity in elevators, basements, or rural delivery routes, but they still need to open job details (address, instructions, safety notes) for their upcoming assignments. To keep the offline experience reliable without bloating storage, the app pre-downloads a limited set of job detail payloads.
You are given a list of jobs the Tasker may need soon. Each job has:
job_id (unique integer)last_updated (integer timestamp; larger means more recent)size_kb (positive integer; offline payload size)priority (integer; larger means more important to keep offline)You have an offline storage budget of capacity_kb. Implement:
def select_jobs_for_offline(jobs: list[tuple[int, int, int, int]], capacity_kb: int) -> list[int]:
Return a list of job_ids to cache such that:
<= capacity_kb.last_updated (prefer fresher data).job_ids is lexicographically smallest.If capacity_kb is too small to fit any job, return an empty list.
Input:
jobs = [(10, 100, 4, 7), (11, 90, 3, 6), (12, 110, 5, 8)], capacity_kb = 7
Output:
[10, 11]
Explanation:
4 + 3 = 7, priority 7 + 6 = 13.Input:
jobs = [(1, 5, 2, 4), (2, 6, 2, 4), (3, 1, 4, 8)], capacity_kb = 4
Output:
[3]
Explanation:
1, jobs 1+2 have 5+6=11, so [1,2] would win by freshness — but it does not fit because 2+2=4 fits; actually it fits, so winner is [1, 2].Note: This example illustrates tie-breaking; ensure your implementation follows rules exactly.
1 <= len(jobs) <= 2000 <= capacity_kb <= 10_0001 <= size_kb <= 10_0000 <= priority <= 10_0000 <= last_updated <= 10^9job_id values are uniquejob_ids in any order, but tie-breaking rule #4 is based on the sorted list of selected IDs.