Задание 17 ЕГЭ по информатике: обработка числовой последовательности
Подтемы
- Задания для подготовки84 задач
Что проверяет задание
Задание 17 проверяет умение писать программу для обработки большого набора данных, хранящегося в файле. Проверяемые навыки — это не абстрактная теория, а практическое программирование: чтение чисел из файла, организация циклов, работа с условными операторами, вычисления по модулю и накопление результата (счётчика и максимума/минимума).
В основе задания всегда лежит одна и та же идея: дана последовательность чисел, нужно рассмотреть пары элементов (либо соседние, либо произвольные), отобрать пары, удовлетворяющие некоторому условию, и вычислить два числа — количество таких пар и максимальную (иногда минимальную) сумму элементов среди отобранных пар.
Задание входит в блок практического программирования и требует не теоретических знаний, а умения быстро и без ошибок реализовать несложный алгоритм на выбранном языке программирования (Pascal, Python, C++, Basic — допускается любой).
Как выглядит формулировка и сколько баллов
Типичная формулировка звучит так: «В файле содержится последовательность целых чисел. Элементы последовательности могут принимать значения от до включительно. Определите и запишите в ответе сначала количество пар элементов, удовлетворяющих условию, затем максимальную из сумм элементов таких пар».
Ключевые параметры, которые меняются от варианта к варианту:
- диапазон значений чисел (например, от до или натуральные числа до );
- количество элементов в последовательности (часто , но может быть и другое число, оно не всегда указано явно и определяется чтением файла до конца);
- тип пары — «два идущих подряд элемента» или «два различных элемента, порядок не важен»;
- условие на пару — делимость на число, чётность/нечётность, различие или совпадение остатков от деления, диапазон значений и т. п.
Ответ записывается в виде двух чисел через пробел: количество подходящих пар и максимальная сумма. Задание оценивается в 1 балл, при этом балл засчитывается только за полностью верный ответ — оба числа должны совпасть с эталонными.
Что нужно знать
- Делимость числа на : .
- Остаток от деления: , где для натуральных чисел; при проверке на равенство нулю знак числа не важен ни в одном языке программирования.
- Число пар без повторов из элементов: .
- Пара соседних элементов последовательности — это при ; всего таких пар .
- Логическое «хотя бы одно из двух» — это операция ИЛИ (or), «оба одновременно» — операция И (and).
- Разность двух чисел чётна тогда и только тогда, когда числа имеют одинаковую чётность: .
- Сложность полного перебора всех пар из элементов — ; при это порядка – операций.
- Числа в файле обычно записаны через пробел или каждое на отдельной строке — язык программирования должен уметь читать оба формата.
Методы решения
1. Метод последовательного просмотра (для соседних пар). Если пара — это два идущих подряд элемента, достаточно одного цикла: пройти по последовательности от первого элемента до предпоследнего и на каждом шаге сравнить и . Сложность .
Мини-пример: для последовательности пары соседей — , всего пары.
2. Метод полного перебора всех пар (для произвольных пар). Когда пара — любые два различных элемента без учёта порядка, используют два вложенных цикла: внешний по индексу от до , внутренний по индексу от до . Так каждая пара учитывается ровно один раз, число пар равно .
Мини-пример: для трёх чисел пары — , то есть .
3. Метод группировки по остаткам или по делимости. Если условие связано с остатком от деления на фиксированное небольшое число или , можно заранее разложить числа по «корзинам» — спискам чисел с одинаковым остатком. Это ускоряет анализ при больших и небольшом , так как позволяет свести сравнение всех пар к сравнению корзин.
Мини-пример: для числа распределятся по остаткам — три числа попадают в корзину «остаток 0».
4. Метод раздельных счётчиков и максимумов по категориям. Условие «хотя бы одно из чисел делится на » удобно обрабатывать, разбив все числа на две группы: делящиеся на и не делящиеся. Тогда искомые пары — это все пары внутри первой группы плюс все пары между первой и второй группой; максимум суммы ищется отдельно в каждой из этих категорий пар.
5. Метод прямой проверки условия внутри цикла без предварительной группировки. Самый универсальный и надёжный способ для экзамена — просто вычислять оба условия прямо в теле цикла (или двух вложенных циклов), без построения дополнительных структур. Он медленнее, но проще и менее подвержен ошибкам — на экзамене надёжность важнее скорости кода.
Алгоритм решения по шагам
- Определить формат входных данных: сколько чисел, в каком диапазоне, как они разделены в файле.
- Прочитать все числа в список (массив) или организовать построчное/поточное чтение.
- Внимательно выделить тип пары — соседние элементы или произвольные два различных элемента без учёта порядка.
- Сформулировать условие на пару в виде логического выражения на языке программирования, точно повторяя формулировку задания (союз «и» — это
and, «хотя бы одно» — этоor). - Организовать цикл (один — для соседних пар, два вложенных — для произвольных пар), на каждом шаге проверять условие.
- При выполнении условия увеличивать счётчик количества пар и сравнивать сумму пары с текущим максимумом, обновляя его при необходимости.
- После завершения цикла вывести два числа: количество и максимальную сумму, разделённые пробелом.
- Проверить решение на приведённом в условии примере входных данных, если он есть — это лучший способ убедиться в правильности программы до отправки на большом файле.
Разбор примеров
Пример 1. Последовательность целых чисел от до . Пара — два идущих подряд элемента. Нужно найти количество пар, где хотя бы одно число делится на , и максимальную сумму среди таких пар.
Шаг 1. Читаем все числа в список seq.
Шаг 2. Так как пара — это соседние элементы, используем один цикл по индексу i от 0 до len(seq)-2.
Шаг 3. Условие: a % 3 == 0 or b % 3 == 0, где a = seq[i], b = seq[i+1]. Проверка на равенство нулю работает верно независимо от знака числа.
Шаг 4. Код на Python:
seq = list(map(int, open('input.txt').read().split()))
count = 0
max_sum = None
for i in range(len(seq) - 1):
a, b = seq[i], seq[i + 1]
if a % 3 == 0 or b % 3 == 0:
count += 1
s = a + b
if max_sum is None or s > max_sum:
max_sum = s
print(count, max_sum)
Шаг 5. Проверка на примере из условия: последовательность . Пары соседей: — делится на , подходит, сумма ; — делится на , подходит, сумма ; — оба делятся на , подходит, сумма ; — оба делятся на , подходит, сумма . Итого пары, максимальная сумма — совпадает с примером из условия («4 11»).
Шаг 6. На реальном файле с элементами эта программа выполнится мгновенно, так как сложность линейна: . Ответ для полного файла — «2802 1990».
Пример 2. Последовательность из натуральных чисел, каждое не больше . Пара — два различных элемента, порядок не важен. Условие: остатки от деления на различны И хотя бы одно число делится на .
Шаг 1. Читаем числа в список seq, длина n = len(seq).
Шаг 2. Так как пара — произвольные различные элементы без учёта порядка, нужны два вложенных цикла: внешний по i от 0 до n-1, внутренний по j от i+1 до n-1.
Шаг 3. Условие для пары (a, b): a % 160 != b % 160 and (a % 7 == 0 or b % 7 == 0).
Шаг 4. Код на Python:
seq = list(map(int, open('input.txt').read().split()))
n = len(seq)
count = 0
max_sum = None
for i in range(n):
for j in range(i + 1, n):
a, b = seq[i], seq[j]
if a % 160 != b % 160 and (a % 7 == 0 or b % 7 == 0):
count += 1
s = a + b
if max_sum is None or s > max_sum:
max_sum = s
print(count, max_sum)
Шаг 5. Проверка на примере из условия: числа . Остатки от деления на : , , , . Делимость на : делится, не делится, не делится, делится.
Перебираем все пар: — остатки и различны, делится на — подходит, сумма ; — остатки и совпадают — не подходит; — остатки и различны, оба делятся на — подходит, сумма ; — остатки и различны, но ни одно не делится на — не подходит; — остатки различны, делится на — подходит, сумма ; — остатки различны, делится на — подходит, сумма . Итого подходящие пары, максимальная сумма — совпадает с примером («4 488»).
Шаг 6. Замечание по сложности: при двойной цикл делает около итераций — на Python это может занять десятки секунд, поэтому на реальном экзамене лучше использовать более быстрый язык (Pascal, C++) или предварительно сгруппировать числа по остаткам, чтобы снизить число сравнений. Итоговый ответ на полном файле — «12749665 19989».
Пример 3. Последовательность из положительных целых чисел, каждое не больше . Пара — два различных элемента, порядок не важен. Условие: разность чётна И хотя бы одно число делится на .
Шаг 1. Заметим, что «разность двух чисел чётна» равносильно тому, что оба числа имеют одинаковую чётность: . Это упрощает проверку.
Шаг 2. Код на Python:
seq = list(map(int, open('input.txt').read().split()))
n = len(seq)
count = 0
max_sum = None
for i in range(n):
for j in range(i + 1, n):
a, b = seq[i], seq[j]
if a % 2 == b % 2 and (a % 31 == 0 or b % 31 == 0):
count += 1
s = a + b
if max_sum is None or s > max_sum:
max_sum = s
print(count, max_sum)
Шаг 3. Логика та же, что и в примере 2: два вложенных цикла перебирают все различные пары без повторов, для каждой пары проверяется составное условие «одинаковая чётность и делимость хотя бы одного числа на 31». Итоговый ответ для полного файла — «1569269 19982».
Шаг 4. Общий вывод из трёх примеров: тип пары (соседние или произвольные) определяет структуру цикла, а условие на пару — это просто логическое выражение, которое нужно аккуратно перевести с русского языка на язык программирования, не путая «и» с «или».
Типичные ошибки и ловушки
- Путаница между «соседними» и «произвольными» парами — из-за этого выбирается неверная структура цикла и получается совершенно другой (обычно намного больший) счётчик пар.
- Учёт пары элемента с самим собой при произвольных парах: внутренний цикл должен начинаться с
j = i + 1, а не сj = i, иначе элемент образует пару с собой, что противоречит условию «два различных элемента». - Двойной учёт одной и той же пары: если перебирать
jот0доn-1без ограниченияj > i, каждая пара считается два раза, что искажает и количество, и не влияет на максимум, но портит первое число ответа. - Ошибка off-by-one при построении пар соседних элементов: цикл должен идти до
n-2(индекс) илиn-1раз, а не доn-1включительно, иначе возникнет выход за границы массива. - Перепутывание «и» и «или»: условие «хотя бы одно из чисел делится на p» — это
or, а «оба числа удовлетворяют условию» — этоand; ошибка здесь меняет ответ радикально. - Неверная трактовка «различные остатки»: нужно явно сравнивать
a % d != b % d, а не путать это с условием неделимости наd. - Забывание, что переменная максимума должна инициализироваться специальным значением (например,
Noneв Python или очень маленьким числом в других языках), а не нулём — иначе при всех отрицательных суммах результат окажется неверным. - Неучёт объёма данных: при и вложенных циклах на интерпретируемых языках программа может работать слишком долго; в компилируемых языках (Pascal, C++) такой перебор укладывается в разумное время.
- Переполнение типов данных в языках со статической типизацией: сумма двух чисел до по модулю не переполняет
integer, но если складывается много элементов или используются другие масштабы — стоит проверять диапазон типа. - Невнимательное чтение формулировки о диапазоне значений: отрицательные числа требуют аккуратной проверки делимости, хотя сама проверка
a % m == 0не зависит от знака в подавляющем большинстве языков.
Как готовиться
Лучший способ подготовки — регулярно писать короткие программы на выбранном языке, отрабатывая именно эту структуру: чтение чисел из файла, цикл (один или два вложенных), логическое условие, накопление счётчика и максимума. Полезно вести шаблон кода, который остаётся неизменным, а меняется только строка с условием — это экономит время на экзамене и снижает риск синтаксических ошибок.
Стоит разобрать как можно больше вариантов условий на пару: делимость на число, различие или совпадение остатков, чётность/нечётность, попадание в диапазон значений, наличие определённой цифры в числе. Каждый раз важно точно определить тип пары — соседние элементы последовательности или любые два различных элемента без учёта порядка — от этого зависит структура цикла.
При тренировке обязательно проверяйте свою программу на небольшом примере входных данных, который часто приводится в самом условии задачи, прежде чем запускать её на большом файле — это позволяет быстро отловить логические ошибки, не дожидаясь результата на тысячах чисел.
Полезно также заранее продумать, на каком языке решать это задание быстрее и увереннее: если предпочтителен Python, стоит помнить о возможной медлительности вложенных циклов при больших объёмах данных и по возможности заранее знать способы группировки чисел по остаткам для ускорения; если выбран Pascal или C++, вложенные циклы для выполняются практически мгновенно, и можно сосредоточиться исключительно на правильности логики условия.
Наконец, регулярно решайте задания из открытого банка и сборников подготовки — разнообразие формулировок условий на пару позволяет довести до автоматизма перевод текстовой формулировки в логическое выражение на языке программирования, а это и есть главный навык, который проверяется в задании 17.
Частые вопросы
Чем отличается пара соседних элементов от произвольной пары?
Соседняя пара — это два элемента, стоящих подряд в последовательности: (a_i, a_{i+1}). Произвольная пара — любые два различных элемента без учёта порядка, таких пар в n-элементной последовательности C_n^2 = n(n-1)/2.
Как правильно перебрать все произвольные пары без повторов?
Нужны два вложенных цикла: внешний по индексу i от 0 до n-1, внутренний по индексу j от i+1 до n-1. Такой перебор гарантирует, что каждая пара учитывается ровно один раз и элемент не образует пару с самим собой.
Как проверить делимость отрицательного числа на модуль?
Проверка a % m == 0 работает верно независимо от знака числа: если число делится на m, остаток от деления равен нулю в любом языке программирования, знак числа на это не влияет.
Что означает условие «различные остатки от деления на d»?
Это означает, что при делении двух чисел на d получаются разные остатки: a % d != b % d. Это не то же самое, что неделимость одного из чисел на d — нужно явно сравнивать остатки друг с другом.
Почему полный перебор пар может быть медленным при n = 10000?
Двойной цикл перебирает порядка n(n-1)/2, то есть около 5*10^7 пар. На компилируемых языках (Pascal, C++) это выполняется за доли секунды, но на интерпретируемых языках вроде Python может занять заметное время, поэтому иногда полезна группировка чисел по остаткам.
Сколько баллов дают за задание 17 и как оценивается ответ?
Задание оценивается в 1 балл, засчитываемый только при полном совпадении обоих чисел ответа — количества пар и максимальной суммы. Частично верный ответ (только одно число) баллов не приносит.
С чего начать проверку своей программы перед отправкой на большом файле?
Нужно вручную или мысленно прогнать программу на небольшом примере входных данных, приведённом в условии задачи, сравнить полученный результат с ожидаемым ответом из примера и только после этого запускать программу на реальном файле с тысячами чисел.