Для простого p все целые числа от 1 до p−1 взаимно просты с ним, поэтому ϕ(p)=p−1. Для степени простого исключаются только числа, кратные p:
ϕ(pe)=pe−pe−1=pe−1(p−1).
Каждое различное простое — один раз
Целое число взаимно просто с n ровно тогда, когда ни один простой делитель n его не делит.
Для каждого простого делителя p исключаем его кратные. Пересечения учитывает формула включений-исключений: для любого выбранного набора различных простых делителей их произведение делит n, поэтому кратных всем им чисел ровно n, делённое на это произведение.
Раскрыв сумму включений-исключений, получаем
ϕ(n)=np∣n∏(1−p1).
Произведение содержит каждое различное простое число только один раз. Его вклад вычисляем целочисленным обновлением
res←res−pres,
начиная с res=n. Предыдущие обновления делят только на другие простые числа, поэтому p по-прежнему делит текущий ответ.
У положительных взаимно простых a,b множества простых делителей не пересекаются. Поэтому та же формула даёт
ϕ(ab)=ϕ(a)ϕ(b).
Вычисляем одно значение
Для исходного значения n это занимает O(n) времени и O(1) дополнительной памяти.
Предподсчёт решетом
Инициализируем t[x]=x. Перебираем кандидатов p в порядке возрастания. Если t[p]=p, то p простое: каждое составное число уже было уменьшено при обработке меньшего простого делителя.
Применяем t[x]←t[x]−t[x]/p к каждому кратному p, начиная с самого p. Это включает обновление ϕ(p)=p−1.
Вызываем phi_sieve(n) для 0≤n≤107. После этого t[x]=ϕ(x) для 1≤x≤n; нулевой элемент не используется. Каждый вызов заново строит таблицу.
Решето занимает O(nloglogn) времени и O(n) памяти. Каждый последующий запрос — обращение к таблице за O(1).
Сумма по делителям
Для каждого делителя d числа n объединим в группу целые k∈[1,n], для которых gcd(k,n)=n/d.
Запишем k=(n/d)j. Тогда 1≤j≤d и gcd(j,d)=1, поэтому в этой группе ϕ(d) чисел. Группы разбивают все n чисел, что даёт
d∣n∑ϕ(d)=n.
Функция Эйлера на отрезке
Для отрезка [L,R], где 1≤L≤R, храним для каждого x из отрезка ответ ax и оставшееся значение rx.
Находим все простые числа до ⌊R⌋.
Инициализируем ax=rx=x.
Для каждого простого p обходим его кратные в [L,R]. Один раз применяем ax←ax, затем удаляем из все вхождения .
Если в конце остался остаток rx>1, применяем ax←ax.
Последний остаток — простое число, потому что список базовых простых покрывает все возможные маленькие делители. Каждое различное простое число вносит вклад ровно один раз, поэтому ax=ϕ(x).
Начинаем обход кратных с ⌈L/p⌉p. Включаем само p, если оно лежит в отрезке, так как для его функции Эйлера тоже нужен вклад этого простого.
Два массива для отрезка занимают O(W) памяти, где W=R−L+1. Подготовка базовых простых решетом добавляет O(R) памяти.
−
ax/p
rx
p
−
ax/rx
#include <bits/stdc++.h>using namespace std;long long phi(long long n){ long long res = n; for(long long p = 2; p <= n / p; p +=(p == 2 ? 1 : 2)){ if(n % p == 0){ res -= res / p; while(n % p == 0){ n /= p;}}} if(n > 1){ res -= res / n;} return res;}
vector<int> t;void phi_sieve(int n){ t.resize(n + 1); for(int x = 0; x <= n; x++){ t[x] = x;} for(int p = 2; p <= n; p++){ if(t[p] != p){ continue;} for(int x = p; x <= n; x += p){ t[x] -= t[x] / p;}}}