Задание 25
Обработка целочисленной информации
Делители парами до корня, простые числа и разложение, маски числа и поиск подходящих чисел в диапазоне.
6 подтем · 53 задачи + 6 дополнительных · высокий · ≈ 20 мин
Подтема 1 из 6
Перебор и запись числа
Что спрашивают в задании 25, как перевести условие в проверки, перебрать числа и проверить цифры записи.
Как устроена тема
В задании 25 программа перебирает числа и проверяет у каждого условие: делимость, делители, простые множители, цифры записи или маску. Вот задача, которую мы решим в этой теме:
«Напишите программу, которая перебирает целые числа, большие 7 000 000, в порядке возрастания и ищет среди них числа, представленные в виде произведения ровно двух простых множителей, не обязательно различных, каждый из которых содержит в своей записи хотя бы одну цифру 1 и хотя бы одну цифру 6. В ответе для первых пяти найденных чисел запишите само число и наибольший из его простых множителей.»
Перебор пишется в пару строк, а вся работа — в проверке: она должна быть верной и быстрой, ведь чисел миллионы. Разберём, что значат слова условия:
| В условии | Что это значит |
|---|---|
| делится без остатка, кратно | остаток равен нулю: n % d == 0 |
| большие 7 000 000, не превышающие 10⁹ | 7 000 000 не берём, 10⁹ — берём |
| делители, не считая единицы и самого числа | делители d, для которых 1 < d < n |
| простое число | больше 1 и делится только на 1 и на само себя |
| произведение простых множителей, не обязательно различных | разложение 12 = 2 · 2 · 3: повторы тоже считаются |
| содержит в записи цифру 6 | проверка строки, а не арифметики: '6' in str(n) |
| маска 12?4*5 | ? — одна любая цифра, * — любые цифры, даже ни одной |
| первые пять найденных | идти от границы вверх, пока не найдено пять |
Начнём с перебора и записи числа — этого уже хватит, чтобы проверить цифры множителей. Потом найдём делители и простые множители и решим задачу темы. Тема состоит из пяти подтем и дополнительного урока — у каждой своя страница:
- Перебор и запись числа — ты сейчас здесь: проверки, перебор, цифры записи.
- Делители парами — поиск делителей до √n, отбор и количество.
- Числа с нужными делителями — ровно k делителей, больше всего делителей, величина M.
- Простые числа и разложение — простые множители; решим задачу темы.
- Маски — знаки ? и *, перебор с шагом и построение чисел по маске.
- Вид числа по количеству делителей — дополнительный урок для огромных диапазонов.
Деление с остатком
Что значит «делится без остатка» и как проверить это в программе?
Число n делится на d, если остаток от деления равен нулю: . Разделим 17 на 5: пятёрка помещается в 17 три раза, и остаются две единицы — 17 = 5 · 3 + 2. В Python частное даёт 17 // 5, это 3, а остаток — 17 % 5, это 2.
n // d, клетки, которым не хватило на порцию, — остаток n % d. Меняй числа или выбери пример.Остаток всегда меньше делителя: будь он больше, из него сложилась бы ещё одна порция. У 20 и 5 порции заполняются ровно — 20 % 5 равно 0, значит, 20 делится на 5. А если число меньше делителя, порции нет совсем: 3 // 7 — это 0, а 3 % 7 — всё число, 3.
Обычное деление / здесь не нужно: 18 / 3 даёт дробное 6.0. Степень для больших границ пишут через **: 10⁹ — это 10 ** 9, а не 10 ^ 9.
Условие — в код
Как перевести слова условия в проверку и не ошибиться на границе?
Слово за словом: «кратно» — остаток ноль, «больше» — строгое сравнение, «не превышает» — нестрогое, «и» — , «или» — or. Похожие формулировки различаются одним знаком. Выбери формулировку:
- кратно 7
n % 7 == 0остаток равен нулю- не кратно 7
n % 7 != 0остаток не ноль;!=— «не равно»- нечётное
n % 2 != 0не делится на 2- больше 100
n > 100само 100 не подходит- не меньше 100
n >= 100100 подходит- не превышает 100
n <= 100100 подходит- на отрезке [100; 200]
100 <= n <= 200обе границы входят
or не значит «ровно одно из двух»: число 15 подходит под «делится на 3 или на 5», хотя делится на оба.
n = 15print(n % 3 == 0 and n % 5 == 0)print(n % 3 == 0 or n % 5 == 0)Перебор отрезка
Как проверить все числа отрезка подряд?
Циклом по range. Правая граница range не входит, поэтому отрезок [L; R] — это range(L, R + 1). Выведем числа отрезка [10; 30], кратные 3:
for n in range(10, 31): if n % 3 == 0: print(n)Граница 31 — чтобы проверить и само 30. А «числа, большие 7 000 000» начинаются с 7 000 001: сама граница в «больше» не входит.
Сколько чисел можно так перебрать? Десять миллионов простых проверок Python делает за секунду-другую, а миллиард — уже за несколько минут. Поэтому в масках будем перебирать умнее.
Число и его запись
Как узнать о числе то, что видно в его записи: сколько в нём цифр, какая последняя, какова сумма цифр?
Превратить число в строку: — это его запись, у неё есть длина и отдельные символы. Последние цифры удобно брать остатком: n % 10, n % 100.
n = 50721s = str(n)print(len(s), s[0], s[-1])print(n % 10, n % 100, n // 100) digit_sum = 0for ch in s: digit_sum += int(ch)print(digit_sum)Пять цифр, первая 5, последняя 1. Остаток от деления на 10 — последняя цифра, на 100 — две последние, а n // 100 отбрасывает их. Сумму цифр считает цикл по символам записи: int(ch) превращает символ «7» в число 7.
Окончание с нулём проверяй по записи: у 7 и у 107 остаток n % 100 один — 7, но на «07» оканчивается только 107. Это проверка str(n).endswith('07').
Цифры в записи
Как проверить условие задачи темы: «множитель содержит в записи цифру 1 и цифру 6»?
Оператором над записью: '1' in s истинно, если символ 1 есть в строке хотя бы раз. Группу цифр ищут так же, а s.count('53') считает, сколько раз она встречается. Проверку двух цифр оформим : в строке с def — её имя и параметр p, а return возвращает ответ — True или False.
def has_1_and_6(p): s = str(p) return '1' in s and '6' in s print(has_1_and_6(61), has_1_and_6(163), has_1_and_6(71))В 61 и 163 есть обе цифры, в 71 нет шестёрки. Такую проверку мы применим к каждому из двух множителей в задаче темы. Другие формулировки про цифры числа n — выбери; везде s = str(n):
- содержит цифру 7
'7' in s- не содержит 0
'0' not in s- есть 2 или 3
'2' in s or '3' in s- «53» ровно один раз
s.count('53') == 1- оканчивается на 37
n % 100 == 37
Когда count ошибается
count ищет вхождения без перекрытий: нашёл группу — продолжает после неё. В 7777 он найдёт 77 дважды, хотя начинаться 77 может с трёх мест:
count: после 77 с позиции 0 поиск идёт с позиции 2, и 77 с позиции 1 пропускается.У групп вроде 53 или 567 начало не совпадает с концом, им перекрываться не с чем, и count прав. Для 77 или 121 сначала пойми, что считает условие.
Первые найденные
В задаче темы нет верхней границы: «перебирает числа, большие 7 000 000, … первые пять найденных». Докуда же идти?
Пока не найдено пять: цикл со счётчиком найденных. Число увеличиваем на каждом шаге, а счётчик — только когда число подошло. Найдём три первых числа больше 1000, которые делятся на 13 и содержат цифру 7:
n = 1001found = 0while found < 3: if n % 13 == 0 and '7' in str(n): print(n) found += 1 n += 1Числа идут по возрастанию и ни одно не пропущено, поэтому первые три успешные проверки — это три наименьших подходящих числа.
Если спрашивают о наибольших числах, идут вниз: range с шагом −1, а после нужного количества цикл прерывает . Нижняя граница 0 не даст уйти в отрицательные числа, если подходящих меньше трёх:
found = []for n in range(999, 0, -1): if n % 13 == 0 and '7' in str(n): found.append(n) if len(found) == 3: break print(found)Итого
- Делится
n % d == 0 - Отрезок [L; R]
range(L, R + 1) - Первые k после Nс N + 1,
while found < k - Наибольшие kвниз по range и break
- Цифры записи
str(n),in,count - Последние цифры
n % 10,n % 100
Проверьте себя
Ответь сначала сам, потом открой ответ.
ОтветСкрыть ответ
n % 2 != 0 and n <= 500: «не превышает» пропускает и само 500.print(17 // 5, 17 % 5, 5 % 17)?ОтветСкрыть ответ
range перебирает числа отрезка [100; 200]? А числа, большие 100, но меньшие 200?ОтветСкрыть ответ
range(100, 201) и range(101, 200): правая граница range не входит.ОтветСкрыть ответ
'616161'.count('61') даёт 3.while found < 5 строку n += 1 поставили внутрь if, рядом с found += 1. Что случится?ОтветСкрыть ответ
Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Найди частное и остаток
Вычисли без Python 145 // 12 и 145 % 12. Затем запиши равенство вида n = d·q + r.
Введите частное и остаток через пробел.
Подсказка
Сколько полных порций по 12 помещается в 145 и сколько остаётся сверх них?
Решение
145 = 12·12 + 1: полных порций по 12 — двенадцать, сверх них остаётся 1. Частное 12, остаток 1, и он меньше делителя 12.
Решение программой
print(145 // 12, 145 % 12)Ответ: 12 1
Посчитай кратные 7, но не 5
Сколько чисел от 1000 до 2000 включительно делятся на 7, но не делятся на 5?
Введите количество чисел.
Подсказка
«Делится на 7, но не делится на 5» — две проверки остатка, соединённые и. Правая граница 2000 входит в отрезок.
Решение
114: из 143 кратных 7 исключаем 29 кратных 35. Программа переводит условие буквально: остаток при делении на 7 равен нулю, а при делении на 5 — нет.
Решение программой
count = 0for n in range(1000, 2001): if n % 7 == 0 and n % 5 != 0: count += 1print(count)Ответ: 114
Посчитай числа, оканчивающиеся на 37
Сколько чисел на отрезке [10 000; 20 000] оканчиваются на 37 и делятся на 3?
Введите количество чисел.
Подсказка
Две последние цифры числа — это остаток от деления на 100.
Решение
33: числа вида …37, кратные 3, идут через 300. Проверка окончания — n % 100 == 37, проверка делимости — n % 3 == 0.
Решение программой
count = 0for n in range(10000, 20001): if n % 100 == 37 and n % 3 == 0: count += 1print(count)Ответ: 33
Посчитай числа с суммой цифр 10
Сколько чисел от 1 до 1000 имеют сумму цифр, равную 10?
Введите количество чисел.
Подсказка
Сумму цифр удобно получить из записи числа: перебрать символы str(n) и сложить их значения.
Решение
63. Для каждого числа сумма цифр складывается из символов его записи; подходят числа, у которых она равна 10.
Решение программой
count = 0for n in range(1, 1001): digit_sum = 0 for ch in str(n): digit_sum += int(ch) if digit_sum == 10: count += 1print(count)Ответ: 63
Сравни count и вхождения с перекрытием
Что вернёт "7777".count("77")? Сколько раз группа 77 входит в 7777, если считать вхождения с перекрытием?
Введите два числа через пробел: что вернёт count и сколько вхождений с перекрытием.
Подсказка
После найденного вхождения count продолжает поиск сразу за ним. Вхождения с перекрытием можно перебрать по позиции начала.
Решение
count вернёт 2; с перекрытием вхождений три: группа 77 начинается с позиций 0, 1 и 2.
Решение программой
s = "7777"overlap = 0for i in range(len(s) - 1): if s[i:i + 2] == "77": overlap += 1print(s.count("77"), overlap)Ответ: 2 3
Посчитай числа с цифрами 1 и 6
Сколько чисел от 1 до 1 000 000 содержат в записи хотя бы одну цифру 1 и хотя бы одну цифру 6?
Введите число.
Подсказка
Это проверка записи: '1' in s and '6' in s, где s = str(n).
Решение
Для каждого числа проверяем две цифры в его записи — так же, как множители в задаче темы.
Решение программой
count = 0for n in range(1, 1000001): s = str(n) if '1' in s and '6' in s: count += 1print(count)Ответ: 199262
Найди три наибольших подходящих числа
Найди три наибольших числа меньше 500 000, которые делятся на 13, оканчиваются цифрой 9 и содержат в записи хотя бы одну цифру 0.
Введите три числа через пробел, от большего к меньшему.
Подсказка
Нужны наибольшие числа — перебирай вниз от 499 999 и остановись, как только найдутся три.
Решение
499109, 498069, 497809. Перебор по убыванию сразу даёт наибольшие подходящие числа, поэтому после третьего найденного цикл можно прервать.
Решение программой
found = []for n in range(499999, 0, -1): if n % 13 == 0 and n % 10 == 9 and "0" in str(n): found.append(n) if len(found) == 3: breakprint(*found)Ответ: 499109 498069 497809
Найди первые числа с двумя семёрками
Найди пять наименьших чисел, больших 1 000 000, которые делятся на 17 и содержат в записи ровно две цифры 7.
Введите пять чисел через пробел в порядке возрастания.
Подсказка
Иди вверх от 1 000 001 циклом while, пока не найдёшь пять; цифры 7 считает str(n).count('7').
Решение
Перебор идёт по возрастанию без пропусков, поэтому первые пять успешных проверок — пять наименьших чисел. Например, 1 000 773 = 17 · 58 869, в записи две семёрки.
Решение программой
n = 1000001found = 0while found < 5: if n % 17 == 0 and str(n).count('7') == 2: print(n) found += 1 n += 1Программа выведет
10007731000977100177610026771002779Ответ: 1000773 1000977 1001776 1002677 1002779