Подтема 2 из 6
Делители парами
Почему делители достаточно искать до √n, как не потерять и не задвоить корень, как отобрать и посчитать нужные делители.
Что такое делитель
Что такое делитель и о каких делителях спрашивает условие?
d — делитель n, если n делится на d без остатка. Условие часто берёт не все делители: без единицы и самого числа, только чётные или только простые. Делители 12 — это 1, 2, 3, 4, 6 и 12: 12 = 1 · 12 = 2 · 6 = 3 · 4. А 5 не делитель: 12 = 5 · 2 + 2. Выбери требование — подходящие делители 12 выделятся:
- все делители
- 1, 2, 3, 4, 6, 12
- кроме 1 и самого числа
- 2, 3, 4, 6
- чётные
- 2, 4, 6, 12
- простые
- 2, 3простые числа разберём в подтеме 4
Единицу и само число исключают, только если условие говорит об этом прямо. Чётные делители 12 включают и само 12.
Делители парами
Как найти все делители числа, не проверяя каждое число до n? Для числа около миллиарда это миллиард проверок, а чисел в задаче — миллионы.
Делители идут парами: если d делит n, то и n // d делит n. Нашёл меньший делитель пары — получил и больший. Это хорошо видно на клетках: из 36 одинаковых клеток прямоугольник без пустых мест складывается пятью способами.
Ширина 4 подходит, потому что 36 делится на 4 — выходит ровно 9 рядов. Ширина 5 не подходит: 36 = 5 · 7 + 1, одна клетка лишняя. Ширина растёт — 1, 2, 3, 4, 6, — а высота падает — 36, 18, 12, 9, 6. На квадрате 6 × 6 они встречаются.
Дальше новых пар нет: ширина 9 — это тот же прямоугольник 4 × 9, только повёрнутый. Сторона квадрата из n клеток называется квадратным корнем из n, √n. Для 36 это 6.
Почему хватает √n
Почему не бывает пары, в которой оба делителя больше √n?
Прямоугольник, у которого обе стороны больше 6, целиком накрывает квадрат 6 × 6 и ещё выходит за него — 36 клеток ему не хватит. Значит, в каждой паре хотя бы один делитель не больше √n.
Поэтому кандидатов d проверяют, только пока d · d ≤ n. Если n не квадрат, граница — целая часть корня: √40 между 6 и 7, и для 40 хватает d до 6. Её точно считает isqrt(n) из модуля math. Выигрыш огромный:
| Число n | До n | До √n |
|---|---|---|
| 10⁶ | 1 000 000 | 1 000 |
| 10⁹ | 1 000 000 000 | 31 622 |
| 10¹² | 1 000 000 000 000 | 1 000 000 |
Обоснование · необязательноДоказательство для любого n
Пусть n = d · q и оба множителя больше √n. Тогда d · q > √n · √n = n — противоречие с d · q = n. Значит, хотя бы один множитель пары не больше √n.
Поиск по шагам
Как программа находит все девять делителей 36, проверив только числа от 1 до 6?
Для каждого d от 1 до √n: если n делится на d, в список идут d и его пара n // d. Пару квадрата 6 · 6 добавляют один раз. Слева на прямой — кандидаты от 1 до 6, справа — их пары. Переключай шаги: у каждого делителя появляется дуга к его паре, а не делитель отмечается крестиком.
- d = 1: 36 % 1 = 0. Сразу два делителя — 1 и 36 // 1 = 36.
- d = 2: 36 % 2 = 0. Сразу два делителя — 2 и 36 // 2 = 18.
- d = 3: 36 % 3 = 0. Сразу два делителя — 3 и 36 // 3 = 12.
- d = 4: 36 % 4 = 0. Сразу два делителя — 4 и 36 // 4 = 9.
- d = 5: 36 % 5 = 1. Не делитель, пары нет.
- d = 6: 36 = 6 · 6. Пара из одного числа — делитель 6 записываем один раз.
- d = 7: 7 · 7 = 49 больше 36 — стоп. Делители: 1, 2, 3, 4, 6, 9, 12, 18, 36.
Все дуги начинаются не правее пунктира √36. Большие делители 9, 12, 18 и 36 программа ни разу не проверяла — она получила их как пары. А на d = 6 пара — само 6, и добавлять его второй раз нельзя: у 36 девять различных делителей, а не десять.
Сам корень проверять обязательно: если для 49 остановиться перед 7, пропадёт делитель 7.
Функция делителей
Делители понадобятся во многих задачах. Как написать поиск один раз и пользоваться им везде?
Оформить его : она получает n и возвращает список его делителей по возрастанию. подключает целый корень.
from math import isqrt def get_divisors(n): divisors = [] for d in range(1, isqrt(n) + 1): if n % d == 0: divisors.append(d) if n // d != d: divisors.append(n // d) return sorted(divisors) print(get_divisors(36))isqrt(n) + 1 — потому что правая граница range не входит, а корень проверить надо. Делители находятся парами, и без список был бы [1, 36, 2, 18, 3, 12, 4, 9, 6]. Функция возвращает список через return, а не печатает: дальше делители будем отбирать, считать и складывать. В следующих подтемах считаем, что она уже написана выше в программе.
Отбор делителей
Как оставить только те делители, о которых спрашивает условие?
Сначала найти все делители, потом отобрать нужные условием на делитель d. Отбор в одну строку записывает : «d для каждого d из делителей, если 1 < d < n».
n = 36D = [d for d in get_divisors(n) if 1 < d < n]print(D)print(len(D), D[0], D[-1], sum(D))Список отсортирован, поэтому наименьший делитель — D[0], наибольший — D[-1], второй по величине — D[-2]. Для других требований меняется только условие — выбери:
- без 1 и n
1 < d < n- без самого числа
d < n- чётные
d % 2 == 0- оканчиваются на 7
d % 10 == 7- кратные 7
d % 7 == 0
Условие стоит на d, а не на n: d % 7 == 0 — «делитель кратен 7», а n % 7 == 0 — «само число кратно 7». И проверяй длину: если в списке один делитель, D[-2] вызовет ошибку.
Почему чётные делители не ищут шагом 2
В паре делителей один может быть нечётным, а другой чётным: 18 = 3 · 6. Если до корня проверять только чётные d, пропадёт 3, а с ним и чётный 6.
Счётчик делителей
Если нужно только количество делителей, зачем хранить их список?
Хватит счётчика: пара разных делителей добавляет 2, пара квадрата d · d = n — 1. — это count = count + 2.
def count_divisors(n): count = 0 for d in range(1, isqrt(n) + 1): if n % d == 0: if d * d == n: count += 1 else: count += 2 return count print(count_divisors(36), count_divisors(40))У 36 пары 1 · 36, 2 · 18, 3 · 12 и 4 · 9 дают по два делителя, а 6 · 6 — один: 2 + 2 + 2 + 2 + 1 = 9. У 40 квадратной пары нет — четыре пары, восемь делителей.
Итого
- Делитель
n % d == 0 - Параd и
n // d - Границаd от 1 до
isqrt(n)включительно - Квадраткорень добавить один раз
- Отборусловие на d, а не на n; список —
sorted - Количество+2 за пару, +1 за корень
Проверьте себя
Ответь сначала сам, потом открой ответ.
ОтветСкрыть ответ
ОтветСкрыть ответ
isqrt(1000) = 31. Делителей 16 — восемь пар от 1 · 1000 до 25 · 40.ОтветСкрыть ответ
get_divisors(30) без sorted? Можно ли тогда брать наибольший делитель как D[-1]?ОтветСкрыть ответ
[1, 30, 2, 15, 3, 10, 5, 6]. Нельзя: последним стоит 6, а наибольший делитель — 30.ОтветСкрыть ответ
Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Сосчитай кандидатов до корня
Сколько кандидатов d проверяет поиск делителей до корня для числа n = 10¹⁰?
Введите число.
Подсказка
Кандидаты — все d от 1 до isqrt(n) включительно.
Решение
√(10¹⁰) = 10⁵, и поиск проверяет d = 1, 2, …, 100 000 — вместо десяти миллиардов при переборе до n.
Решение программой
from math import isqrt print(isqrt(10**10))Ответ: 100000
Посчитай делители миллиона
Сколько натуральных делителей у числа 1 000 000?
Введите число.
Подсказка
get_divisors найдёт их парами до isqrt(1 000 000) = 1000; осталось взять длину списка.
Решение
Функция проверяет d от 1 до 1000 и к каждому найденному делителю добавляет пару 1 000 000 // d; корень 1000 добавляется один раз.
Решение программой
from math import isqrt def get_divisors(n): divisors = [] for d in range(1, isqrt(n) + 1): if n % d == 0: divisors.append(d) if n // d != d: divisors.append(n // d) return sorted(divisors) print(len(get_divisors(1000000)))Ответ: 49
Выпиши чётные делители 90
Выпиши все чётные делители числа 90.
Введите делители через пробел в порядке возрастания.
Подсказка
Сначала найди все делители, затем оставь те, что делятся на 2.
Решение
2, 6, 10, 18, 30, 90. Условие проверяется у делителя d, а не у числа 90.
Решение программой
from math import isqrt def get_divisors(n): divisors = [] for d in range(1, isqrt(n) + 1): if n % d == 0: divisors.append(d) q = n // d if q != d: divisors.append(q) return sorted(divisors) D = [d for d in get_divisors(90) if d % 2 == 0]print(*D)Ответ: 2 6 10 18 30 90
Найди числа с четырьмя делителями без 1 и n
Найди все числа на отрезке [312 400; 312 450], у которых ровно четыре различных натуральных делителя, не считая единицы и самого числа. Для каждого числа выведи эти делители в порядке возрастания.
Запишите все строки ответа подряд в одну строку через пробел: в каждой строке число и его четыре делителя по возрастанию.
Подсказка
Для каждого числа отрезка найди делители, оставь 1 < d < n и проверь, что их ровно четыре. Обе границы отрезка входят в перебор.
Решение
Подходят два числа: 312404 с делителями 2, 4, 78101, 156202 и 312425 с делителями 5, 25, 12497, 62485.
Решение программой
from math import isqrt def get_divisors(n): divisors = [] for d in range(1, isqrt(n) + 1): if n % d == 0: divisors.append(d) q = n // d if q != d: divisors.append(q) return sorted(divisors) for n in range(312400, 312451): D = [d for d in get_divisors(n) if 1 < d < n] if len(D) == 4: print(n, *D)Программа выведет
312404 2 4 78101 156202312425 5 25 12497 62485Ответ: 312404 2 4 78101 156202 312425 5 25 12497 62485
Найди числа с 16 чётными делителями
Найди все числа отрезка [512 340; 512 360], у которых не менее 16 различных чётных делителей. Для каждого выведи само число и его наибольший чётный делитель, не равный самому числу.
Запишите все строки ответа подряд в одну строку через пробел: в каждой строке число и его наибольший чётный делитель.
Подсказка
Отбери чётные делители условием d % 2 == 0 и посчитай их. Наибольший, не равный n, ищи среди d != n.
Решение
У нечётного числа чётных делителей нет вовсе. Наибольший чётный делитель меньше n — это n / 2, если оно чётное; иначе ищем дальше: у 512 358 это 170 786 = 512 358 / 3.
Решение программой
from math import isqrt def get_divisors(n): divisors = [] for d in range(1, isqrt(n) + 1): if n % d == 0: divisors.append(d) if n // d != d: divisors.append(n // d) return sorted(divisors) for n in range(512340, 512361): E = [d for d in get_divisors(n) if d % 2 == 0] if len(E) >= 16: print(n, max(d for d in E if d != n))Программа выведет
512340 256170512344 256172512352 256176512356 256178512358 170786Ответ: 512340 256170 512344 256172 512352 256176 512356 256178 512358 170786
Посчитай делители 360
Сколько натуральных делителей у числа 360? Посчитай функцией count_divisors.
Введите количество делителей.
Подсказка
Ищи делители парами до isqrt(n): обычная пара добавляет 2, пара вида d · d = n — 1.
Решение
24. Счётчику не нужен список: каждая найденная пара разных делителей добавляет два, а 360 не квадрат, поэтому пар из одного числа нет.
Решение программой
from math import isqrt def count_divisors(n): count = 0 for d in range(1, isqrt(n) + 1): if n % d == 0: if d * d == n: count += 1 else: count += 2 return count print(count_divisors(360))Ответ: 24