Editorial for Imperfecciones


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Author: aniervs

Si \sigma(i) es la suma de los divisores de i, entonces la solución es simplemente \sum_{i = A}^B |2i - \sigma(i)|. Entonces, necesitamos calcular todos los \sigma(i) eficientemente.


Sabemos que la suma de los divisores de un número se puede calcular a partir de sus divisores primos. Si N = p_1^{a_1}\cdot p_2^{a_2}\cdot ... \cdot p_k^{a_k}, donde cada p_i es un primo distinto, y a_i es un entero no negativo; entonces la suma de los divisores de N es:

\displaystyle \sigma(N) = \left(\dfrac{p_1^{a_1+1}-1}{p_1 - 1}\right) \left(\dfrac{p_2^{a_2+1}-1}{p_2 - 1}\right)\dots \left(\dfrac{p_k^{a_k+1}-1}{p_k - 1}\right)

Si lo vemos recurrentemente:

\displaystyle \sigma(N) = \left(\frac{p_1^{a_1+1}-1}{p_1 - 1}\right) \cdot \sigma\left(\frac{N}{p_1^{a_1}}\right)

Para sacar los primos, usaremos la criba extendida.

Criba Extendida:

Computemos para cada número, un primo que lo divida. O sea, tendremos la tabla p[], donde p[i] es un primo divisor de i. Para hacerlo, primero consideramos que todos los números son primos (es decir, p[i] = i); luego iteramos por todos los números i, y si el número actual es primo (p[i]==i), iteramos por sus múltiplos j, y actualizamos p[j] = i. Se le pueden hacer unas pequeñas optimizaciones para obtener complejidad O(n\log\log n).

Una vez teniendo p[], podemos usar la recurrencia de arriba para calcular \sigma(x) para cada x.

Código de ejemplo:

for(int i = 3; i <= 1e7; i+=2)
    p[i] = i;

for(int i = 2; i <= 1e7; i+=2)
    p[i] = 2;

for(int i = 3; i * i <= 1e7; i+=2)
    if(p[i] == i)
        for(int j = i*i; j <= 1e7; j+=2*i)
            p[j] = i;

sigma[1] = 1;
for(int i = 2; i < maxn; i++){
    int j = i;  
    long long k = p[i];
    while(j % p[i] == 0){
        j /= p[i];
        k *= p[i];
    }

    k = (k - 1)/(p[i] - 1);

    sigma[i] = sigma[j] * k;
}

long long ans = 0;
for(int i = a; i <= b; i++)
    ans += abs(2ll * i - sigma[i]);

Comments

There are no comments at the moment.