Divisor Analysis
Complejidad temporal: .
Cantidad de divisores
Cada divisor del número se puede escribir como donde .
Como hay elecciones para , la cantidad de divisores es simplemente .
Podemos calcular esto recorriendo los factores primos en tiempo .
Suma de divisores
Sea la suma de divisores considerando solo los primeros factores primos. La respuesta será .
Podemos calcular cada usando exponenciación rápida e inversos modulares en tiempo .
Producto de divisores
Sean y el producto y la cantidad de divisores considerando solo los primeros factores primos, respectivamente. La respuesta será .
De nuevo, podemos calcular cada usando exponenciación rápida en tiempo , ¡pero hay un detalle! Puede ser tentador usar de los valores calculados previamente en la parte 1 de este problema, pero esos valores van a dar respuestas incorrectas.
Esto es porque en general. Sin embargo, por el pequeño teorema de Fermat, para primo, así que podemos guardar módulo para calcular .
¿Cómo obtenemos esta recurrencia?
Claramente
porque todos los son primos. Luego para , tenemos
Generalizando a , tenemos
La aparición de en lugar de se debe a que necesitamos dar a todos los divisores previos un multiplicador de . Simplificando, tenemos
que es la recurrencia deseada. Notar que .
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll MOD = 1e9 + 7;
ll expo(ll base, ll pow) {
ll ans = 1;
while (pow) {
if (pow & 1) ans = ans * base % MOD;
base = base * base % MOD;
pow >>= 1;
}
return ans;
}
ll p[100001], k[100001];
int main() {
cin.tie(0)->sync_with_stdio(0);
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> p[i] >> k[i];
ll div_cnt = 1, div_sum = 1, div_prod = 1, div_cnt2 = 1;
for (int i = 0; i < n; i++) {
div_cnt = div_cnt * (k[i] + 1) % MOD;
div_sum =
div_sum * (expo(p[i], k[i] + 1) - 1) % MOD * expo(p[i] - 1, MOD - 2) % MOD;
div_prod = expo(div_prod, k[i] + 1) *
expo(expo(p[i], (k[i] * (k[i] + 1) / 2)), div_cnt2) % MOD;
div_cnt2 = div_cnt2 * (k[i] + 1) % (MOD - 1);
}
cout << div_cnt << ' ' << div_sum << ' ' << div_prod;
return 0;
}