Задание 25: Программирование. Обработка целочисленных данных
1. Общая информация о задании
- Уровень сложности: высокий (Часть 2)
- Максимальный балл: 1
- Примерное время выполнения: около 20 минут
- Формат ответа: обычно таблица из 5 пар чисел — в первом столбце найденные числа, во втором — связанная величина (частное, сумма делителей, множитель…)
Суть: перебрать натуральные числа в заданном диапазоне и найти первые 5, удовлетворяющих условию. Ручной перебор невозможен — нужна программа на Python с оптимизацией цикла.
Задания: N25. Банк заданий | Учебник future-step
Материалы курса:
- Часть 1 — маски чисел, модуль fnmatch
- Часть 2 — делители, последние цифры
- Часть 3 — простые делители, произведение простых
2. Три типа заданий
| Тип | Условие | Основной инструмент |
|---|---|---|
| 1 | Число соответствует маске и делится на заданное число | fnmatch + перебор с шагом |
| 2 | Свойства делителей числа (сумма, мин/макс, окончание на цифру…) | isqrt + перебор делителей |
| 3 | Простые делители, произведение двух простых, сумма простых делителей… | is_prime + делители |
На экзамене сначала определи тип, затем выбери шаблон. Ответ — первые 5 подходящих чисел в порядке возрастания.
3. Тип 1: маски чисел (fnmatch)
Когда: в условии дана маска — последовательность цифр с символами:
?— ровно одна произвольная цифра;*— любая последовательность цифр (в том числе пустая).
Число должно также делиться на заданное rem без остатка.
Подстановочные знаки
| Знак | Значение | Пример |
|---|---|---|
* |
любые символы (в т.ч. пусто) | 4*1 → 41, 447361 |
? |
ровно один символ | 3?5 → 305, 395 |
[1-5] |
одна цифра из набора | a[1-5] → a1…a5 |
[!13579] |
один символ, не из набора | a[!13579] → a2, a4… |
Шаблон решения
from fnmatch import fnmatch
mask = '3?12?14*5' # маска из условия
rem = 1917 # делитель из условия
start = 30120145 # минимальное число под маску (см. ниже)
limit = 10 ** 10 # верхняя граница из условия
for i in range(start + (-start % rem), limit, rem):
if fnmatch(str(i), mask):
print(i, i // rem)
Как найти start (нижнюю границу маски):
- Удалить все
*. - Вместо каждого
?поставить0(для минимального числа).
Пример: маска 33*21?7 → 332107; маска 4*4736*1 → 447361.
Оптимизация перебора:
- шаг цикла =
rem(число из условия «делится на …»); - старт:
start + (-start % rem)— первое число ≥start, кратноеrem.
fnmatchпроверяет всю строку целиком (какre.fullmatch). Число передаём черезstr(i).
Пример (задание 2520)
Маска 3?12?14*5, делитель 1917, числа ≤ 10¹⁰.
from fnmatch import fnmatch
for i in range(30120145 + (-30120145 % 1917), 10 ** 10, 1917):
if fnmatch(str(i), '3?12?14*5'):
print(i, i // 1917)
4. Тип 2: делители числа
Когда: нужно найти делители числа и проверить их свойства — сумму, минимум/максимум, окончание на цифру.
Эффективный поиск всех делителей
Делители идут парами: если i — делитель, то num // i — тоже. Достаточно перебрать i от 1 до √num.
from math import isqrt
def get_divisors(num):
divisors = set()
for i in range(1, isqrt(num) + 1):
if num % i == 0:
divisors |= {i, num // i}
return divisors
Для числа 1 000 000: перебор до
num— ~1 000 000 итераций; доisqrt(num)— ~1 000.
Последние цифры числа
| Задача | Код |
|---|---|
| последняя цифра | num % 10 |
| две последние цифры | num % 100 |
| три последние цифры | num % 1000 |
| оканчивается на 11 | num % 100 == 11 |
Предпочтительнее % — быстрее, чем str(num)[-1].
Типичные формулировки
| Обозначение | Что считать |
|---|---|
| R — сумма всех делителей | R = sum(get_divisors(num)) |
| M — сумма min и max делителей (без 1 и самого числа) | найти первый делитель i ≥ 2, тогда M = i + num // i |
| делитель, оканчивающийся на 11 | перебор i до √num, проверка i % 100 == 11 и пары num // i |
Шаблон: сумма делителей R оканчивается на 6
from math import isqrt
def f(num):
divisors = set()
for i in range(1, isqrt(num) + 1):
if num % i == 0:
divisors |= {i, num // i}
R = sum(divisors)
if R % 10 == 6:
return R
return 0
cnt = 0
for i in range(500_001, 10 ** 20):
if R := f(i):
print(i, R)
cnt += 1
if cnt == 5:
break
Оптимизация: нужны только min и max делители
Если условие касается только минимального и максимального делителя (не считая 1 и num), не собирай всё множество — достаточно первого найденного делителя i ≥ 2:
from math import isqrt
def f(num):
for i in range(2, isqrt(num) + 1):
if num % i == 0:
M = i + num // i
if M % 10 == 4:
return M
return 0
return 0
Шаблон: делитель, оканчивающийся на 11
from math import isqrt
def f(num):
for i in range(2, isqrt(num) + 1):
if num % i == 0:
if i % 100 == 11 and i != 11:
return i
j = num // i
if j % 100 == 11 and j != 11:
return j
return 0
5. Тип 3: простые делители
Когда: среди делителей нужны простые числа; число — произведение ровно двух простых множителей; сумма min и max простых делителей.
Проверка простоты (алгоритм 6k±1)
from math import isqrt
def is_prime(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
if n == 3:
return True
if n % 3 == 0:
return False
for div in range(5, isqrt(n) + 1, 6):
if n % div == 0 or n % (div + 2) == 0:
return False
return True
Единица не простое число. Число 2 — единственное чётное простое.
Простые делители числа
def get_prime_divisors(num):
return {d for d in get_divisors(num) if is_prime(d)}
Произведение ровно двух простых (полупростое число)
Перебираем делитель i от 2 до √num. Если num % i == 0, второй множитель j = num // i. Оба должны быть простыми.
from math import isqrt
def contains_digit(num, digit):
return str(num).count(str(digit)) == 1
def f(num):
for i in range(2, isqrt(num) + 1):
if num % i == 0:
j = num // i
if contains_digit(i, 5) and contains_digit(j, 5):
if is_prime(i) and is_prime(j):
return max(i, j)
return 0
Порядок проверок: сначала быстрые (contains_digit), потом медленные (is_prime).
Сумма min и max простых делителей M
def f(num):
divisors = [d for d in get_divisors(num) if is_prime(d)]
if not divisors:
return 0
M = min(divisors) + max(divisors)
if M > 60_000 and str(M) == str(M)[::-1]: # палиндром
return M
return 0
6. Общий каркас программы
Почти все задачи 25 укладываются в одну схему:
cnt = 0
for i in range(START + 1, 10 ** 20): # START — из условия «больше N»
if result := check(i): # функция проверки
print(i, result)
cnt += 1
if cnt == 5:
break
| Параметр | Откуда брать |
|---|---|
START |
«больше 500 000» → range(500_001, …) |
check(i) |
возвращает связанное значение или 0 / False |
result |
то, что пишется во второй столбец ответа |
cnt == 5 |
в условии всегда «первые пять» |
Оператор := (морж) удобен для присваивания внутри if:
if R := f(i):
print(i, R)
7. Полезные операции
| Что делаем | Код |
|---|---|
| Целочисленный корень | from math import isqrt → isqrt(n) |
| Делимость без остатка | num % i == 0 |
| Целочисленное деление | num // i |
| Первое кратное ≥ start | start + (-start % rem) |
| Проверка маски | fnmatch(str(i), mask) |
| Количество цифры в записи | str(num).count('5') |
| Палиндром | s == s[::-1] где s = str(num) |
| Сумма делителей | sum(get_divisors(num)) |
Модуль fnmatch — шпаргалка
from fnmatch import fnmatch, filter
fnmatch('30120145', '3?12?14*5') # True / False
filter(['a1b', 'ab'], 'a?b') # ['a1b']
8. Алгоритм решения на экзамене
- Прочитать условие: диапазон, что искать, сколько чисел вывести
- Определить тип (1 — маска, 2 — делители, 3 — простые)
- Выписать формулу для второго столбца (R, M, частное, множитель…)
- Написать функцию
check(num)или цикл сfnmatch - Оптимизировать: шаг по делителю, нижняя граница маски, не искать лишние делители
- Вывести 5 пар, проверить на маленьком примере вручную
- Убрать отладочные
print
9. Типичные ошибки
| Ошибка | Как избежать |
|---|---|
Перебор всех чисел с шагом 1 при делимости на rem |
Шаг цикла = rem |
range(500_000, …) вместо 500_001 |
«больше N» → начинать с N + 1 |
Забыли str(i) в fnmatch |
Маска работает со строками |
Перебор делителей до num |
Достаточно до isqrt(num) |
Путают i и num // i |
При делителе i пара — num // i |
| Считают 1 простым числом | 1 не простое |
| Функция-предикат возвращает число | is_prime → только True/False |
| Не останавливаются на 5 числах | cnt == 5: break |
start % rem вместо -start % rem |
Для первого кратного используй start + (-start % rem) |
10. Краткий чек-лист
- Какой тип? (маска / делители / простые)
- Что писать во второй столбец?
- С какого числа начинать перебор?
- Можно ли ускорить цикл (шаг,
isqrt, ранний выход)? - Написать код, вывести 5 пар
- Проверить ответ