Editorial for Pares Satisfactorios
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Tratemos de iterar por todas los pares que son soluciones.
Obviamente . Iteremos por todos los posibles valores de
, y para cada
, iteremos por cada posible
, tal que
.
Para un
fijo, iteramos por
valores de
, por lo cual en total se iteran por
pares
.
Una vez que está fijo, tenemos que
. Si tenemos el valor de
, entonces el valor de
puede tomar cualquier divisor de
que sea menor que
; podemos iterar por estos divisores y guardar copias únicas en un arreglo, luego añadimos a la respuesta la cantidad de valores distintos de
visitados.
Entonces:
- primero precomputamos para cada número
un vector con sus divisores.
- Luego iteramos por
; por cada
:
- iteramos por
, y por cada
:
- tenemos
,
- iteramos por los divisores
de
hasta que
.
- tenemos
- Para un
fijo, marcamos los valores de
que visitamos (
mark[a] = true
), - luego añadimos a la respuesta cuántos valores están marcados;
- por último limpiamos el arreglo con el marcamos los números.
- iteramos por
Complejidad temporal: Sea la máxima cantidad de divisores de un número
, entonces podemos acotar la complejidad temporal de esta solución a
. Se puede ver que
, pero esta cota es mucho mayor que la real, ya que no todos los números tienen
divisores.
#include<bits/stdc++.h>
using namespace std;
const int maxn = (int)3e5 + 5;
typedef long long ll;
vector<int> divs[maxn];
bool mark[maxn];
int aux[maxn];
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n; i++){
for(int j = i; j <= n; j+=i){
divs[j].push_back(i);
}
}
ll ans = 0;
for(int b = 2; b < n; b++){
int co = 0;
for(int by = b; by < n; by+=b){
int ax = n - by;
for(int a:divs[ax]){
if(a >= b)
break;
if(!mark[a]){
aux[co++] = a;
mark[a] = 1;
}
}
}
ans += co;
for(int i = 0; i < co; i++)
mark[aux[i]] = 0;
}
cout << ans;
return 0;
}
Comments