Факторизация
Построим вычисление факторизации по массиву lp. Отмечу, что можно отказаться от деления в алгоритме, если в решете подсчитать массив множителей x. Факторизацию мы подсчитаем за логарифмическое время (количество простых делителей числа).
| vector<pair<int, int > > factorization(int a, const vector<int> & lp) { vector<int > rs; // делитель добавлен столько раз, сколько входит в разложение // причём делители будут добавляться по возрастанию while (a!= 1) { rs.push_back(lp[a]); a /= lp[a]; } return rs; } |
Мультипликативная функция
это функция у которой выполняются следующие свойства
1) f(1) = 1
2) f(x*y) = f(x) * f(y), если gcd(x, y) = 1
Примеры
● f(x) = x
● f(x) = x == 1
● f(x) = 1
● O0(x) - количество делителей числа x. Если a и b взаимно просты, то каждый делитель произведения a*b может быть единственным образом представлен в виде произведения делителей a и b, и обратно, каждое такое произведение является делителем a*b. Отсюда следует, что функция τ мультипликативна.
● O1(x) - сумма делителей числа x. Верно по тем же соображениям
● pfi(x) - функция эйлера, количество эйлера, от 1 до x, что взаимно просты с x, доказали ранее
Мультипликативные функции можно считать с помощью линейного решета Эратосфена особенно если для степеней простых чисел данная функция считается просто. Пусть нам нужно f(i), если i = p**k * j, где p минимальный простой делитель i, в степени равной степени его вхождения в факторизацию. Тогда то f(i) = f(p**k) * f(j), в линейном решете можно хранить не только минимальный простой делитель, но и сколько раз он входит в число.
Приведём реализацию функции Эйлера, и использованием массива lp, но без дополнительных предподсчётов, которые могли бы ускорить решение - асимптотика уже будет за логарифм.
| int getEuler(int x, const vector<int> & lp) { // x >= 1 int rs = x, t = x; while (t!= 1) { int div = lp[t]; t /= div; rs -= rs / div; while (t % div == 0) t /= div; } return rs; } |






