Editorial for La progresión armónica
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Queremos resolver . Consideremos . Entonces queremos resolver Es bien conocido cómo factorizar esta ecuación, pero igual lo ponemos aquí:
Multiplicando por a ambos lados de la ecuación, obtenemos , que es lo mismo que . Restamos a ambos lados de la ecuación, obteniendo:
Ahora sacamos factor común con los términos y , y factor común con los términos y , obteniendo , luego sacamos factor común una vez más -esta vez sería -, obteniendo . Multiplicando por a ambos lados obtenemos
Queríamos llegar esa factorización. Ahora sustituimos , quedando , que es lo mismo que
Notemos que es entero, y y también lo son. Por tanto, y son divisores de . Entonces, solo debemos considerar las parejas de números , tales que , (es decir, los divisores de ), y para cada pareja, y toman valores únicos. Si estamos analizando la pareja , entonces , y , por lo que , y . Solo contamos los que sean enteros positivos.
Quedan varias cosas por analizar:
La primera es acotar la cantidad de divisores de . Es bien conocido que la cantidad de divisores de , para , es de orden . Como queremos los divisores de , y , tenemos cerca de divisores en el peor caso, lo cual es suficientemente pequeño.
Bien, ya sabemos cuántos divisores son como mucho. Ahora, cómo iterar por los divisores de , porque incluso cuando son pocos, iterar por todos los números chequeando si son o no divisores resulta costoso.
Veamos este subproblema de manera más general: Dado , computar los divisores de . Para hacerlo, consideremos la factorización en primos de ; digamos que , donde cada es un primo distinto y cada es un entero positivo. Cada divisor de se representa con exactamente los mismos primos de , y con exponentes no negativos menores o iguales a los exponentes de . Por tanto, podemos probar todas las combinaciones , (con ), y para cada combinación generar el número , el cual es un nuevo divisor de . Para probar todas las combinaciones podemos hacer backtracking.
- Ahí surge un problema, cómo factorizar . Es sencillo factorizar en tiempo , pero en este caso . Por suerte, la factorización de es simplemente la misma factorización de , solo con los exponentes duplicados. Entonces, podemos factorizar , lo cual tomaría operaciones, que si nos podemos permitir.
Resumen:
- El problema se reduce a contar las soluciones enteras de la ecuación .
- Hay una correspondencia 1-1 entre las parejas de divisores de , y las parejas de soluciones . Por tanto el problema se reduce a buscar los divisores de .
- Para hacerlo, factorizamos , duplicamos todos los exponentes, obtenemos ese arreglo de exponentes , y hacemos un backtracking probando todos los posibles arreglos de exponentes , con para cada . Para cada uno de esos exponentes, sacamos el divisor resultante, y vemos si conduce a una pareja válida.
Complejiad temporal: .
Código de ejemplo:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> par;
typedef pair<ll,int> ii;
vector<par> ans;
vector<ii> v;
void factorize(int x){
for(ll i = 2; i*i <= x; i++){
int cnt = 0;
while(x % i == 0){
x /= i;
cnt++;
}
if(cnt > 0) v.push_back({i,2*cnt});
}
if(x > 1) v.push_back({x,2});
}
ll b, n;
void bct(int id, ll d){
if(d > b) return;
if(id == v.size()){
ll p = n/d;
if(d % 2 != b % 2) return;
if(p % 2 != b % 2) return;
ll a = (d + b)/2;
ll c = (p + b)/2;
if(a > c) swap(a,c);
ans.push_back({a,c});
if(a != c) ans.push_back({a,c});
return;
}
bct(id+1,d);
ll cur = 1;
for(int i = 0; i < v[id].second; i++){
cur *= v[id].first;
bct(id+1,d*cur);
}
}
int main(){
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> b;
n = b*b;
factorize(b);
bct(0,1);
sort(ans.begin(), ans.end());
cout << ans.size() << '\n';
for(par it:ans)
cout << it.first << ' '<< it.second <<'\n';
return 0;
}
Comments