К содержанию

Подтема 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 одинаковых клеток прямоугольник без пустых мест складывается пятью способами.

Все прямоугольники из 36 клеток. Ширина и высота каждого — пара делителей 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.

Квадрат 6 × 6 — это уже все 36 клеток. Прямоугольник 7 × 8 содержит его и ещё клетки вокруг: в нём 56 клеток.

Поэтому кандидатов d проверяют, только пока d · d ≤ n. Если n не квадрат, граница — целая часть корня: √40 между 6 и 7, и для 40 хватает d до 6. Её точно считает isqrt(n) из модуля math. Выигрыш огромный:

Число nДо nДо √n
10⁶1 000 0001 000
10⁹1 000 000 00031 622
10¹²1 000 000 000 0001 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, справа — их пары. Переключай шаги: у каждого делителя появляется дуга к его паре, а не делитель отмечается крестиком.

  1. d = 1: 36 % 1 = 0. Сразу два делителя — 1 и 36 // 1 = 36.
  2. d = 2: 36 % 2 = 0. Сразу два делителя — 2 и 36 // 2 = 18.
  3. d = 3: 36 % 3 = 0. Сразу два делителя — 3 и 36 // 3 = 12.
  4. d = 4: 36 % 4 = 0. Сразу два делителя — 4 и 36 // 4 = 9.
  5. d = 5: 36 % 5 = 1. Не делитель, пары нет.
  6. d = 6: 36 = 6 · 6. Пара из одного числа — делитель 6 записываем один раз.
  7. 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))
[1, 2, 3, 4, 6, 9, 12, 18, 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))
[2, 3, 4, 6, 9, 12, 18] 7 2 18 54

Список отсортирован, поэтому наименьший делитель — 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.

Делители 18 парами, чётные закрашены. Пунктир — √18 ≈ 4,24. Чётные кандидаты 2 и 4 находят только пару (2, 9); чётные 6 и 18 стоят в парах с нечётными 3 и 1.

Счётчик делителей

Если нужно только количество делителей, зачем хранить их список?

Хватит счётчика: пара разных делителей добавляет 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))
9 8

У 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 за корень

Проверьте себя

Ответь сначала сам, потом открой ответ.

Вопрос 1
Выпиши делители 28: все, без единицы и самого числа и только чётные.
ОтветСкрыть ответ
Ответ
Все — 1, 2, 4, 7, 14, 28; без 1 и 28 — 2, 4, 7, 14; чётные — 2, 4, 14, 28.
Вопрос 2
До какого d проверяет кандидатов поиск делителей числа 1000? Сколько делителей он найдёт?
ОтветСкрыть ответ
Ответ
До 31: isqrt(1000) = 31. Делителей 16 — восемь пар от 1 · 1000 до 25 · 40.
Вопрос 3
Почему поиск делителей 49 должен проверить d = 7, но добавить 7 в список только один раз?
ОтветСкрыть ответ
Ответ
Пара 7 · 7 лежит ровно на границе: если остановиться перед 7, делитель потеряется. Но оба числа пары одинаковые, поэтому делитель здесь один.
Вопрос 4
Что вернёт get_divisors(30) без sorted? Можно ли тогда брать наибольший делитель как D[-1]?
ОтветСкрыть ответ
Ответ
[1, 30, 2, 15, 3, 10, 5, 6]. Нельзя: последним стоит 6, а наибольший делитель — 30.
Вопрос 5
Сколько делителей у числа 100? Посчитай парами.
ОтветСкрыть ответ
Ответ
9: пары 1 · 100, 2 · 50, 4 · 25 и 5 · 20 дают по два делителя, а 10 · 10 — один.

Практика

Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.

Сосчитай кандидатов до корня

Сколько кандидатов d проверяет поиск делителей до корня для числа n = 10¹⁰?

Введите число.

Посчитай делители миллиона

Сколько натуральных делителей у числа 1 000 000?

Введите число.

Выпиши чётные делители 90

Выпиши все чётные делители числа 90.

Введите делители через пробел в порядке возрастания.

Найди числа с четырьмя делителями без 1 и n

Найди все числа на отрезке [312 400; 312 450], у которых ровно четыре различных натуральных делителя, не считая единицы и самого числа. Для каждого числа выведи эти делители в порядке возрастания.

Запишите все строки ответа подряд в одну строку через пробел: в каждой строке число и его четыре делителя по возрастанию.

Найди числа с 16 чётными делителями

Найди все числа отрезка [512 340; 512 360], у которых не менее 16 различных чётных делителей. Для каждого выведи само число и его наибольший чётный делитель, не равный самому числу.

Запишите все строки ответа подряд в одну строку через пробел: в каждой строке число и его наибольший чётный делитель.

Посчитай делители 360

Сколько натуральных делителей у числа 360? Посчитай функцией count_divisors.

Введите количество делителей.