Skip to Content

Counting Coprime Pairs

Explicación

Un enfoque de fuerza bruta verificaría cada par (i,j)(i, j) y calcularía gcd(ai,aj)\gcd(a_i, a_j). Esto toma tiempo O(N2logA)\mathcal{O}(N^2 \log A), que es demasiado lento para NN grandes.

En lugar de verificar directamente si gcd(x,y)=1\gcd(x, y) = 1, contamos pares agrupándolos según su gcd.


¿Cómo agruparlos?

Sea:

  • count[d] = número de elementos del arreglo divisibles por dd.
  • pairs[d] = número de pares cuyo gcd es exactamente dd.

Si count[d] elementos son divisibles por dd, entonces el número de pares no ordenados entre ellos es:

(count[d]2)=count[d](count[d]1)2 \binom{\text{count}[d]}{2} = \frac{\text{count}[d] \cdot (\text{count}[d] - 1)}{2}

Sin embargo, esto cuenta pares cuyo gcd es dd, 2d2d, 3d3d y así sucesivamente.

Así que debemos restar los pares sobrecontados.


Paso 1: Contar múltiplos

Para cada dd de 11 a maxVal\text{maxVal}, iteramos sobre sus múltiplos:

count[d] += freq[multiple]

Después de este bucle, count[d] guarda cuántos números son divisibles por dd.

Este preprocesamiento corre en tiempo armónico:

d=1AAd=O(AlogA) \sum_{d=1}^{A} \frac{A}{d} = \mathcal{O}(A \log A)

Paso 2: Inclusión-exclusión sobre el GCD

Ahora calculamos pairs[d] desde el dd más grande hacia 11.

Para un dd fijo:

  1. Empezamos con todos los pares divisibles por dd:

    total=(count[d]2) \text{total} = \binom{\text{count}[d]}{2}
  2. Restamos los pares ya asignados a múltiplos de dd:

    pairs[d]=totalk2pairs[kd] \text{pairs}[d] = \text{total} - \sum_{k \ge 2} \text{pairs}[k \cdot d]

¿Por qué funciona esto?

  • Cada par con gcd igual a algún múltiplo kdk d se incluyó en total.
  • Como procesamos en orden decreciente de dd, todos los pairs[k*d] ya están calculados.
  • Restarlos deja solo los pares cuyo gcd es exactamente dd.

Esto es inclusión-exclusión clásica sobre divisores.

Se nos pide contar pares que son coprimos, es decir, gcd(x, y) = 1. Así que la respuesta es pairs[1].


Implementación

Complejidad temporal: O(AlogA+N)\mathcal{O}(A \log A + N),

#include <bits/stdc++.h> using namespace std; const int MAXA = 1e6 + 5; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; vector<int> freq(MAXA, 0); int maxVal = 0; int x; for (int i = 0; i < n; ++i) { cin >> x; freq[x]++; maxVal = max(maxVal, x); } vector<long long> count(maxVal + 1, 0); vector<long long> pairs(maxVal + 1, 0); for (int d = 1; d <= maxVal; ++d) for (int mult = d; mult <= maxVal; mult += d) count[d] += freq[mult]; // Inclusion - Exclusion Principle for (int d = maxVal; d >= 1; --d) { long long total = count[d] * (count[d] - 1) / 2; for (int mult = 2 * d; mult <= maxVal; mult += d) total -= pairs[mult]; pairs[d] = total; } cout << pairs[1] << '\n'; return 0; }