Теория
Что нужно знать
Задание 26 — это программа, которая обрабатывает большой файл: читает числа или строки, сортирует их, отбирает подходящие объекты и находит две характеристики. Ответ — два целых числа, и оба должны быть верны, иначе вместо двух баллов будет один. В 2027 году проверяется умение обрабатывать целочисленную информацию с использованием сортировки.
Файл и формат ответа
Почти всегда данные лежат в приложенном файле 26.txt. Первая строка задаёт размер и параметры, дальше идут N строк с числами или полями. В ответ нужно записать два целых числа через пробел — обычно количество и характеристику, но порядок задаёт условие.
- Прочитайте первую строку отдельно: в ней могут быть N, K, S, M или сразу несколько параметров.
- Строк может быть от нескольких сотен до миллиона: держите решение линейным или O(N log N).
- Сначала выводится то число, которое в условии названо первым; перепутанный порядок — ноль баллов.
- Если верно только одно число из двух, ставится 1 балл, поэтому проверяйте оба ответа.
- Уточните единицы измерения второго ответа: минуты, килограммы, Кбайты, номер ряда.
- В конце программа должна вывести ровно два числа, без пояснений и лишних строк.
n, limit = map(int, f.readline().split())print(first, second)
Чтение и хранение данных
Файл читают построчно, чтобы не держать в памяти лишние строки. Если в строке несколько полей, удобно сразу превратить её в кортеж чисел. Для поиска по ключу используйте словарь, для проверки повторений — множество.
- with open('26.txt') as f: закрывает файл автоматически; на экзамене допустимо и open(...).readline().
- n = int(f.readline()) — когда первая строка содержит одно число.
- a = [int(x) for x in f] — когда дальше идёт по одному числу в строке.
- data = [tuple(map(int, line.split())) for line in f] — когда полей несколько.
- Для K устройств хватит массива длины K, для N объектов — длины N; не путайте эти размеры.
- Словарь d[key] и множество экономят время, когда значения — номера, артикулы или идентификаторы.
data = [tuple(map(int, line.split())) for line in f]d[key] = d.get(key, 0) + 1
Сортировка и ключи
Сортировка — главная операция задания 26. Она позволяет за один проход выбирать самые лёгкие предметы, ставить рядом подходящие пары и находить разрывы в рядах. Ключ задаёт, по какому полю сортировать и как разрешать равенства.
- a.sort() сортирует по возрастанию, a.sort(reverse=True) — по убыванию.
- a.sort(key=lambda x: x[1]) сортирует по второму полю; key=lambda x: (x[0], -x[1]) — по двум правилам.
- Кортежи сравниваются слева направо: (start, end) сначала по началу, затем по концу.
- Для интервалов часто нужна сортировка по правому концу, для заявок — по времени начала.
- Сортировка в Python устойчивая: при равных ключах сохраняется исходный порядок; это важно, если условие ссылается на порядок в файле.
- sorted(...) возвращает новый список, list.sort() меняет существующий.
a.sort(key=lambda x: (-x[1], x[0]))a.sort(key=lambda x: x[1])
Фильтрация и агрегаты
После чтения отбросьте строки, которые не подходят под условие, и посчитайте нужные величины. Сумму, минимум и максимум лучше накапливать в одном проходе, а не пересчитывать для каждого элемента.
- [x for x in a if cond] оставляет подходящие элементы.
- sum(a), min(a), max(a), len(a) — базовые агрегаты.
- sum(1 for x in a if cond) считает количество подходящих элементов.
- Среднее sum(a) / len(a) — дробное; сравнивать с ним лучше через умножение, чтобы не ловить ошибки округления.
- Два лучших значения ищите одним проходом: обновляйте лучший и второй результат.
- Не вызывайте sum(a) внутри цикла по a: это превращает линейный алгоритм в квадратичный.
sum(1 for x in a if x % 2 == 0)avg = sum(a) / len(a)
Жадный выбор предметов
Классическая схема задания 26: есть N предметов с весом или объёмом и ограничение S. Чтобы взять как можно больше предметов, берут самые лёгкие. Когда количество уже максимально, второе число получают заменой одного выбранного предмета на более выгодный.
- Отсортируйте предметы по возрастанию и накапливайте сумму, пока она не превысит S.
- В отсортированном массиве первый не влезший предмет означает, что все следующие тоже не влезут, — можно остановиться.
- Чтобы максимизировать один предмет при том же количестве, освободите место, убрав последний выбранный предмет.
- Подходящий кандидат x должен помещаться: x <= S - (total - last).
- Жадность по весу не работает для «максимальной стоимости» с произвольными ценностями — там нужна динамика; в 26-м обычно максимизируют количество.
- Проверьте, что один и тот же предмет не выбран дважды: кандидатов берите из ещё не выбранной части массива.
total + x <= Sx <= S - (total - last)
Два указателя и бинарный поиск
Если массив отсортирован, пары и тройки можно искать без полного перебора. Два указателя двигаются только вперёд, поэтому получается O(N) или O(N²) вместо O(N³). Для вопроса «сколько чисел меньше X» подходит bisect.
- Для суммы пары: l = 0, r = n - 1; если сумма мала — l += 1, если велика — r -= 1.
- Для треугольника стороны a <= b <= c достаточно проверить a + b > c.
- Перебирая i и j, двигайте правую границу r, пока a[i] + a[j] > a[r]; все k от j + 1 до r - 1 дают треугольник.
- Количество подходящих троек добавляется как r - j - 1.
- Для каждой потребности ищите минимальный подходящий предмет через bisect_left.
- Сложность перебора троек O(N²) допустима при N до нескольких тысяч, но не при 10^5.
a[i] + a[j] > a[r]bisect_left(a, x)
K устройств и заявки
Во многих задачах K одинаковых исполнителей обслуживают поток заявок: курьеры, такси, репетиторы, компьютеры, камеры хранения. Заявки сортируют по времени начала, а для каждого исполнителя хранят момент освобождения.
- free = [0] * K — время, когда исполнитель снова доступен.
- Ищите первый по номеру свободный объект: if free[i] <= start или free[i] < start, если освобождение доступно только со следующей минуты.
- Перерыв задаётся так: free[i] + rest <= start.
- Если свободных нет, заявка отклоняется; считайте обслуженные и отклонённые отдельно.
- Второй ответ — номер последнего использованного исполнителя, максимум прибыли или число отказов.
- Для камер хранения с типами и объёмами сначала фильтруйте по типу и объёму, затем выбирайте минимальный объём и минимальный номер.
- При больших K линейный поиск каждого исполнителя станет медленным — тогда нужна куча heapq.
free[i] <= startfree[i] + rest <= start
Интервалы и события
Задачи про одновременные события решаются сканирующей прямой. Начало интервала даёт +1, конец -1; после сортировки событий баланс показывает, сколько событий активно в каждой точке.
- events.append((l, 1)) и events.append((r, -1)); сортируйте по времени.
- Если отрезки [1; 5] и [5; 8] считаются пересекающимися, при равном времени сначала обрабатывайте начало, потом конец.
- Если события в одной точке совместимы (конец одного и начало другого), порядок обратный: сначала конец.
- Максимум активных — это максимальное значение баланса после обработки события.
- Длину промежутка с максимумом считайте как сумму t - prev, пока баланс равен максимуму.
- Количество пересекающихся пар: при обработке начала прибавьте текущий баланс — столько активных интервалов пересекается с новым.
- Для вопроса «сколько событий шло одновременно» не нужно строить массив на 10^9 точек: хватит 2N событий.
bal += deltaans = max(ans, bal)
Покрытие отрезков
Задачи про камеры, ремонт дороги и подрядчиков — это покрытие отрезков. Минимальное число точек, покрывающих все интервалы, даёт жадность по правому концу. Если нужно покрыть заданный отрезок [A; B], сортируют по левому концу и на каждом шаге берут самый дальний правый конец.
- Для минимального числа камер: сортировка по правому концу; камера ставится в правый конец первого непокрытого отрезка.
- Следующий отрезок уже покрыт, если его левый конец не больше последней камеры.
- Для покрытия [A; B]: среди отрезков с L <= A выбирайте максимальный R, затем переносите A в этот R.
- Второй ответ «максимальное начало последнего участка» требует отдельной проверки кандидатов, заканчивающихся за B.
- Для минимального расстояния между последними камерами рассматривают два жадных прохода: слева направо и справа налево.
- Проверяйте, включены ли границы: L <= A и R >= B.
if L > last_camera: поставить камеру в RA = max_R
Группировка по ключу
Если объекты описываются парой «ключ — значение» (ряд и место, артикул и цена, клиент и объём), сначала соберите их в словарь. Затем обрабатывайте каждую группу отдельно: сортируйте, считайте сумму, ищите разрывы или максимум.
- d.setdefault(key, []).append(value) собирает список по ключу.
- collections.defaultdict(list) делает то же самое короче.
- Для мест в ряду используйте множество: быстро проверять занятость и искать свободные подряд места.
- Для артикулов храните количество, сумму и остаток; итог считайте после чтения всех строк.
- Для пар «цвет + диаметр» ключом может быть кортеж (color, size).
- При равных агрегатах уточните правило: больший или меньший номер, порядок в файле, минимальная цена.
- Не сортируйте весь словарь, если нужен только максимум: достаточно пройти по значениям.
d.setdefault(row, set()).add(seat)d[(color, size)] = d.get((color, size), 0) + 1
Накопительная сумма и резервные копии
В новых вариантах встречается журнал сервера: запросы добавляют данные в буфер ограниченного объёма. Когда очередной запрос не помещается, сервер сохраняет резервную копию текущего буфера и начинает заполнять его заново.
- Храните текущий объём cur и список объёмов копий backups.
- Перед добавлением проверяйте cur + volume > limit; если да — добавьте cur в копии и обнулите буфер.
- После проверки добавляйте объём запроса: cur += volume.
- Суммы по клиентам удобно копить в словаре client -> volume.
- Ограничение по времени применяйте к сумме и к копиям отдельно: сравнивайте время как строку ЧЧ:ММ:СС или переводите в секунды.
- Второй ответ — сумма двух последних или двух наибольших копий; читайте формулировку внимательно.
- Если запрос сам больше буфера, уточните в условии, что считается копией; обычно такие данные не встречаются.
if cur + v > K: backups.append(cur); cur = 0cur += v
Сложность и проверка
При N = 10^5–10^6 сортировка O(N log N) работает за секунды, а двойной перебор O(N²) — нет. Отдельно следите за памятью: массив на 10^9 элементов не поместится, а словарь на N ключей — поместится.
- O(N log N) — сортировка; O(N) — один проход, два указателя, события.
- O(N²) допустим для N до 2–5 тысяч, но не для 10^5.
- Не создавайте массивы размером с максимальную координату, если координаты до 10^9: используйте словарь или сжатие.
- Проверьте пустой ввод, один элемент, равные значения и границы <= и <.
- Сверьте ответ на маленьком примере из условия, если он есть.
- Убедитесь, что выведены оба числа в нужном порядке и без лишнего текста.
N = 10^6: O(N log N) — норма, O(N^2) — нет