Задание 27 ЕГЭ по информатике: кластеризация чисел и обработка больших файлов
Подтемы
- Кластеризация45 задач
- Задания для подготовки43 задач
Что проверяет задание
Задание 27 — практическое программирование, где нужно написать программу, обрабатывающую поток числовых данных и вычисляющую заданную величину (сумму, произведение, количество пар и т.п.) по правилу, связанному с делимостью или остатками. Проверяются: умение переводить словесное условие в алгоритм; знание базовых структур данных (массивы, счётчики, частотные таблицы); умение оценивать сложность алгоритма и писать эффективные (обычно линейные) решения, способные обработать до элементов за разумное время; аккуратность в целочисленной арифметике. Ключевая идея большинства таких задач — кластеризация: разбиение чисел на несколько групп по общему признаку (остаток от деления, тип делимости на простые множители модуля), чтобы заменить полный перебор пар агрегированными вычислениями по группам.
Как выглядит формулировка и сколько баллов
Типичная формулировка: дана последовательность чисел или пар чисел (до – элементов), нужно вычислить сумму/произведение/количество пар, удовлетворяющих условию делимости или максимальности при ограничении. Входные данные — два файла: А (маленький, можно решить и перебором) и B (большой, переборный алгоритм не успеет отработать). В ответе указываются два числа — результат для файла А и для файла B, в этом порядке. За задание дают 2 балла: по одному за каждый файл, если программа выдаёт верный ответ и использует принципиально верный (не экспоненциальный) алгоритм. Достаточно приложить программу и итоговые числа — важен именно результат.
Что нужно знать
- Остаток от деления: — число от до , такое что .
- Делимость: делится на тогда и только тогда, когда .
- Разложение модуля на простые множители — ключ к решению: , .
- Произведение делится на (простые ), если множители и в сумме «набираются» у и : одно число делится на , либо одно делится на , другое — на .
- Число пар внутри одной группы размера : .
- Число пар между двумя разными группами размерами и : .
- Сложность: полный перебор пар — , при это операций (слишком долго); проход с группировкой — или .
- При и элементах до сумма может достигать , произведение — до ; в C++/Pascal нужен 64-битный тип, в Python переполнения нет.
Методы решения
1. Линейный проход с накоплением. Проходим по данным один раз, храня нужные агрегаты. Пример: для каждой пары выбрать большее и сложить — вычисляется за один проход.
2. Кластеризация по остаткам. Разбиваем числа на группы по остатку от деления на модуль, связанный с условием (на 2, 3, 7, 13 и т.д.). Внутри каждой группы храним количество элементов, сумму, максимум или топ-несколько значений. Пример: для делимости на 26 получаем 4 кластера — «делится на 26», «делится на 13, не на 2», «делится на 2, не на 13», «прочие».
3. Жадная минимальная коррекция. Если оптимальная сумма не удовлетворяет дополнительному ограничению, ищем минимальное изменение, переводящее её в допустимое состояние. Пример: сумма максимумов — находим минимальную «потерю» среди пар, где , и меняем выбор именно в этой паре.
4. Топ-к элементов в кластере. Для поиска оптимальной комбинации (например, максимального произведения) при нескольких условиях делимости достаточно хранить 2–3 наибольших значения каждого типа и проверять только эти кандидаты.
5. Комбинаторный подсчёт пар по кластерам. Вместо перебора всех пар считаем количество валидных пар через размеры кластеров: внутри «подходящего» кластера — по формуле сочетаний, между «дополняющими» кластерами — произведением их размеров.
Алгоритм решения по шагам
- Прочитать входные данные: количество элементов и сами значения.
- Определить признак, связанный с условием (остаток от деления или простые множители модуля из условия).
- Завести переменные-агрегаты для каждого кластера (количество, сумма, максимум, топ-несколько значений).
- Один раз пройти по элементам, распределяя каждый в соответствующий кластер и обновляя агрегаты.
- По собранным агрегатам применить формулу задачи (суммирование, , , минимальная коррекция, перебор top-k) — без обращения ко всему массиву.
- Повторить для обоих файлов (маленький можно проверить и перебором) и вывести оба числа в требуемом порядке.
Разбор примеров
Пример 1 (максимальная сумма, не кратная 3). Из каждой пары выбираем число так, чтобы сумма была максимальна и не делилась на 3. Шаг 1. Для каждой пары берём , считаем . Шаг 2. Если — это ответ. Шаг 3. Если , заменяем в одной паре максимум на минимум, теряя . Сумма не кратна 3, если . Берём минимальное такое . На данных из условия: пары . Максимумы: , , . Разности: ; остатки по модулю 3: . Минимальная разность с ненулевым остатком — (пара ). Ответ: — совпадает с условием. Тот же алгоритм на файлах A и B даёт суммы и .
Пример 2 (наибольшее произведение, кратное 14). . Произведение делится на 14, если хотя бы одно число делится на 14 само, либо одно делится на 7 (не обязательно на 2), а другое — на 2 (не обязательно на 7). Шаг 1. Классифицируем каждое число: делится на 14; делится на 7, не на 2; делится на 2, не на 7; прочие. Шаг 2. Для группы «делится на 14» умножаем любое такое число на максимум из всех остальных. Шаг 3. Для комбинации «7, не 2» и «2, не 7» берём максимум каждой группы и умножаем. Шаг 4. Ответ — максимум из шагов 2–3. На примере из условия: числа . Число делится на 14, максимум среди остальных — , произведение совпадает с демонстрационным ответом. Тот же метод на файлах A и B даёт и .
Пример 3 (количество пар с произведением, кратным 26). . Кластеры: «кратно 26» (), «кратно 13, не 2» (), «кратно 2, не 13» (), «прочие». Пары, дающие произведение кратное 26: пары с участием кластера 26 (считаются через общее число пар минус пары без него) плюс пары «13,не2» с «2,не13» — их количество . На маленьком примере: числа . Кластер «кратно 26» пуст; «кратно 13, не 2» — (); «кратно 2, не 13» — (); произведение совпадает с ответом из условия. Этот же метод на файлах A и B даёт и .
Типичные ошибки и ловушки
- Полный перебор пар на большом файле — программа не успевает выполниться, балл за файл B теряется.
- Переполнение целочисленного типа: суммы до , произведения до — в C++/Pascal нужен
long long/int64. - Ошибка при определении «дополняющих» кластеров: число, кратное сразу двум множителям модуля, нельзя относить к кластеру «только один из множителей».
- Использование вместо при подсчёте пар внутри одного кластера — результат завышается.
- В задачах на «максимум при ограничении» проверка только одной случайной коррекции вместо поиска минимальной по всем кандидатам.
- Путаница «пара различных элементов» с использованием одного элемента дважды.
- Отсутствие проверки программы на демонстрационном примере из условия перед запуском на большом файле.
Как готовиться
Разбирайте задачи по единому шаблону: сначала определите признак делимости или остатка, лежащий в основе условия, затем продумайте, какие агрегаты (суммы, счётчики, максимумы) нужно хранить по кластерам вместо перебора всех элементов. Решайте «в две попытки» — сначала переборный вариант, проверенный на маленьком демонстрационном примере, затем эффективный алгоритм, сравнённый с тем же примером. Тренируйтесь оценивать сложность решения на бумаге: если при получается больше – операций, алгоритм нужно переработать. Держите под рукой набор типовых модулей (2, 3, 7, 13, 14, 26 и их комбинации) и формул комбинаторики (, ). Регулярно решайте варианты прошлых лет именно этого номера, обращая внимание на пару «файл А — файл B»: если алгоритм одинаково быстро работает на обоих файлах, вы на верном пути.
Частые вопросы
Сколько баллов можно получить за задание 27?
Обычно 2 балла: по одному за правильный ответ по каждому из двух файлов — маленькому (файл А) и большому (файл B).
Можно ли решить оба файла одним и тем же переборным алгоритмом?
Файл А — да, но файл B содержит до 10^5 элементов, и алгоритм O(n^2) не успеет выполниться, поэтому нужен эффективный O(n) или O(n log n) подход.
Как понять, по какому признаку кластеризовать числа?
Нужно разложить модуль из условия на простые множители (например, 14=2·7, 26=2·13) и классифицировать числа по делимости на эти множители.
Какой тип данных использовать для сумм и произведений?
При значениях до 10^4 и n до 10^5 суммы могут достигать 10^9, а произведения — 10^10, поэтому в C++/Pascal нужен long long/int64; в Python переполнения нет.
Как проверить правильность эффективного алгоритма перед запуском на большом файле?
Нужно сравнить его результат с переборным алгоритмом на маленьком демонстрационном примере из условия — совпадение ответов подтверждает корректность логики.
Как считать количество пар без полного перебора?
Через размеры кластеров: пары внутри одного кластера считаются по формуле сочетаний k(k-1)/2, а пары между разными дополняющими кластерами — произведением их размеров k·l.
Что делать, если оптимальная сумма не удовлетворяет ограничению по делимости?
Нужно найти минимальное изменение (замену выбора в одной паре), которое переводит остаток суммы в допустимое значение, а не пересчитывать всё заново.