Теория
Что нужно знать
Задание 17 проверяет обработку последовательности чисел из файла: нужно найти количество подходящих пар, троек или окон и второй агрегат — максимум, минимум, сумму или среднее. В базе Kompege по теме 984 задачи, 66 решений (63 программных и 3 текстовых) и 232 видеоразбора (144 YouTube, 53 VK, 35 Rutube). В 2027 году тема сохраняется без изменения номера.
Файл и данные
В задании 17 числа лежат в текстовом файле, обычно по одному в строке. Программа читает весь файл в список целых чисел и дальше работает с ним по индексам. Файл 17.txt лежит рядом с программой; при запуске из другой папки путь нужно указывать явно.
- a = [int(x) for x in open('17.txt')] читает все строки файла.
- strip() нужен, если в файле есть пустые строки или пробелы: int(x.strip()).
- Если числа могут быть в одной строке: a = list(map(int, open('17.txt').read().split())).
- len(a) — количество чисел; допустимые индексы от 0 до len(a) − 1.
- Файл можно не закрывать в короткой программе, но с with open(...) as f надёжнее.
- Храните весь список: опорное значение может стоять в конце файла.
a = [int(x) for x in open('17.txt')]n = len(a)
Каркас решения
Почти все задачи 17 решаются по одной схеме: прочитать данные, найти опорное число по всему файлу, пройти по окнам, проверить условия, собрать подходящие суммы и вывести количество и второй агрегат.
- Шаг 1: прочитать последовательность.
- Шаг 2: найти максимум, минимум, среднее или количество по всему файлу.
- Шаг 3: пройти окна нужной длины.
- Шаг 4: проверить все условия задачи и добавить сумму окна в список.
- Шаг 5: вывести len(b) и max(b), min(b), sum(b) или среднее.
- Если подходящих окон нет, max упадёт — проверьте, что ответ существует.
b = [] — суммы подходящих оконprint(len(b), max(b))
Окна фиксированной длины
Пара — два подряд идущих элемента, тройка — три, четвёрка — четыре. Окно длины k задаётся начальным индексом i и занимает элементы a[i]…a[i+k−1]. Число окон равно n−k+1, а не n−k: последнее окно заканчивается на последнем элементе.
- Пара: a[i], a[i+1], цикл range(n-1).
- Тройка: a[i:i+3], цикл range(n-2).
- Окно длины k: range(n-k+1), последний начальный индекс n-k.
- zip(a, a[1:], a[2:]) — короткий способ идти по тройкам.
- Для пар «через один» берите a[i] и a[i+2].
- Для четвёрок и пятёрок срез a[i:i+k] короче и понятнее.
окон = n − k + 1for i in range(n - k + 1): w = a[i:i+k]
Опорное число
Во многих условиях есть «максимальный элемент, оканчивающийся на 13» или «минимальный двузначный, кратный сумме цифр». Такое число ищут один раз по всему файлу до основного цикла. Внутри цикла его уже не пересчитывают.
- M = max(x for x in a if 10 <= x <= 99 and x % 10 == 3).
- Для отрицательных чисел используйте abs(x) в условиях на цифры.
- Гарантия «такой элемент есть» позволяет не обрабатывать пустой генератор.
- При равенстве максимумов значение всё равно одно и то же.
- Если условие сложное, оформите его функцией-предикатом.
- Опорное число может быть характеристикой всего файла, а не окна.
M = max(x for x in a if P(x))m = min(x for x in a if Q(x))
Ровно, хотя бы, только один
В Python True — это 1, а False — 0. Поэтому число выполненных условий считают суммой логических выражений. Это самый короткий способ реализовать «ровно два из трёх», «хотя бы один» и «только один».
- «Ровно k»: sum(cond(x) for x in w) == k.
- «Хотя бы один»: any(cond(x) for x in w) или sum(...) >= 1.
- «Ни один»: not any(...).
- «Все»: all(cond(x) for x in w).
- «Только один» для двух элементов: cond(x) ^ cond(y), исключающее ИЛИ.
- Для двух разных условий: (P and not Q) or (Q and not P).
sum(bool) == kany(...), all(...), ^
Цифры числа
Свойства цифр проще всего проверять через строку str(abs(x)). Модуль убирает минус, иначе он попадёт в строку и испортит длину и сумму цифр.
- Количество цифр: len(str(abs(x))).
- Последняя цифра: abs(x) % 10, две последние: abs(x) % 100.
- Сумма цифр: sum(map(int, str(abs(x)))).
- Произведение цифр: цикл или prod из math.
- Первая цифра: str(abs(x))[0].
- Палиндром: s == s[::-1].
- Цифра в середине трёхзначного числа: str(abs(x))[1].
- Порядок цифр: сравните список цифр с sorted(...).
digits = str(abs(x))sum(map(int, digits))
Делимость и остатки
Делимость проверяют остатком %: число делится на d, если x % d == 0. Для отрицательных чисел в Python остаток неотрицательный, поэтому −14 % 7 == 0, а −3 % 10 == 7. Если важна именно последняя цифра, берите модуль.
- x % d == 0 — делится на d.
- abs(x) % 10 == 3 — оканчивается на 3, в том числе для отрицательных.
- x % 2 == 0 — чётное; x % 2 == 1 — нечётное.
- Сумма делится на d: (x + y) % d == 0.
- Произведение делится на d: (x * y) % d == 0.
- Разность кратна d: (x - y) % d == 0.
- Остаток от деления на 1000 — последние три цифры.
- Для кратности произведению проверяйте произведение целиком.
x % d == 0abs(x) % 100 == 13
Простые, квадраты, НОД
Проверка простоты — цикл до корня. Полный квадрат надёжнее проверять через isqrt, а не через x ** 0.5: плавающая точка даёт ошибки на больших числах. НОД и НОК берут из модуля math.
- Простое: n >= 2 и нет делителей от 2 до isqrt(n).
- Полный квадрат: r = isqrt(x); r*r == x при x >= 0.
- НОД: gcd(x, y), НОК: x // gcd(x, y) * y.
- Взаимная простота: gcd(x, y) == 1.
- Количество делителей считают перебором до корня.
- math.prod удобен для произведения цифр или элементов окна.
all(n % d for d in range(2, isqrt(n) + 1))gcd(x, y), x*y // gcd(x, y)
Системы счисления
В задании 17 часто встречаются условия про запись в семеричной, восьмеричной или шестнадцатеричной системе. Последняя цифра в системе p — это x % p, а старшую цифру находят делением на p, пока число не станет меньше p.
- bin(x), oct(x), hex(x) дают строку с префиксом.
- Последняя цифра в base p: x % p для неотрицательных чисел.
- Старшая цифра: повторяйте x //= p, пока x >= p.
- Количество цифр: цикл делений или длина строки перевода.
- Перевести число в base p: собирайте остатки с конца.
- «Оканчивается на 23 в base 6» — это x % 36 == 15.
- Для отрицательных сначала берите модуль.
x % p — последняя цифраx % p**k — последние k цифр(23)₆ = 2·6 + 3 = 15
Пары любых элементов i < j
Иногда пара — это не два соседних элемента, а любые два различных элемента, порядок не важен. Полный двойной цикл делает около n²/2 проверок: при n = 10 000 это 50 млн, что на Python медленно. Если условие зависит от остатков, считайте частоты.
- Полный перебор: for i in range(n): for j in range(i+1, n).
- j начинается с i+1, иначе элемент сочетается сам с собой.
- Для суммы, кратной d, храните количество предыдущих остатков.
- Нужный остаток: need = (-x) % d.
- Для максимума суммы храните максимальное значение по остатку.
- «Хотя бы один делится на d» разбивайте на два счётчика.
- Для произведения по модулю d перемножайте остатки по модулю d.
need = (-x) % dcount += cnt[need]
Кольцо, симметрия и расстояние
В закольцованной последовательности после последнего элемента идёт первый: индекс берут по модулю длины. Симметричные пары стоят на равном расстоянии от концов. Тройки на равном расстоянии делят последовательность на три части.
- Сосед справа по кругу: a[(i+1) % n], слева: a[(i-1) % n].
- Окно по кругу: индексы (i+k) % n.
- Симметричная пара: a[i] и a[n-1-i].
- Центральный элемент при нечётной длине в пары не входит.
- Тройки на расстоянии d = n//3: zip(a, a[d:], a[2*d:]).
- Для кольца из n элементов окно длины k даёт ровно n окон.
(i + 1) % na[i], a[n - 1 - i]d = n // 3
Агрегаты ответа
Почти всегда ответ — два числа: количество подходящих окон и второй агрегат. Вторым агрегатом бывает максимум, минимум, сумма всех сумм, среднее арифметическое или характеристика лучшего окна. Внимательно читайте, что именно просят.
- Количество: len(b).
- Максимум суммы: max(b), минимум: min(b).
- Сумма всех найденных сумм: sum(b).
- Среднее с целой частью: sum(b) // len(b).
- Максимальный элемент среди окон: max(max(w) for w in windows).
- Если нужен сам элемент, собирайте элементы, а не суммы.
- Начальное значение для максимума: None или очень маленькое число.
- −10**18 безопаснее, чем 0, если ответ может быть отрицательным.
len(b), max(b), min(b), sum(b)sum(b) // len(b)
Проверка и отладка
Перед запуском на большом файле проверьте программу на маленьком примере из условия. Если в условии есть разобранный пример, сравните оба числа. Затем проверьте границы: первое и последнее окно, отрицательные числа и пустой список результатов.
- Начните с примера из условия: он есть у многих задач.
- Сделайте файл из 5–10 чисел и посчитайте ответ вручную.
- Проверьте последнее окно: оно должно заканчиваться на a[n-1].
- Проверьте отрицательные числа в условиях на цифры.
- Убедитесь, что порядок вывода: сначала количество, потом второй агрегат.
- Если ответ не совпал, выведите несколько первых подходящих окон.
- Сравните len(b) и количество итераций цикла.
print(len(b), max(b))print(b[:5]) для отладки