Coppie con quadrato perfetto#12428

Coppie con quadrato perfetto (Editoriale)

Qualsiasi numero naturale è rappresentabile in modo unico nella forma i = k \cdot x^2, dove è libero da quadrati, cioè non è divisibile per il quadrato di alcun numero primo. Il numero si chiama parte libera da quadrati del numero . Lo indichiamo con . Ad esempio:

Teorema. Il prodotto a \cdot b è un quadrato perfetto se e solo se sf[a] = sf[b].

Dimostrazione. Siano

a = k_1 \cdot x_2, \\ b = k_2 \cdot y_2,

dove k_1 e k_2 sono liberi da quadrati. Allora

a * b = k_1k_2 \cdot (xy)^2

Questa espressione è un quadrato perfetto se e solo se k_1k_2 è un quadrato perfetto. Ma i numeri k_1 e k_2 sono liberi da quadrati. Di conseguenza k_1k_2 è un quadrato perfetto solo se k_1 = k_2.

Riduzione al conteggio dei gruppi. Dal teorema segue che i numeri da a si suddividono in gruppi in base al valore , e la coppia è valida (a \cdot b è un quadrato perfetto) se e solo se e appartengono allo stesso gruppo.

Sia uguale al numero di numeri i~(1 \le i \le n) per cui sf[i] = k. Per calcolarlo è sufficiente eseguire per ogni l'operazione cnt[sf[i]]++.

Se in un gruppo ci sono numeri, esso dà

C_m^2 = \frac{m \cdot (m - 1)}{2}

coppie. La risposta è uguale alla somma su tutti i gruppi:

\sum_k \frac{cnt[k] \cdot(cnt[k] - 1)}{2}

Divisore primo minimo. Per calcolare rapidamente introduciamo un array , uguale al minimo divisore primo del numero . Ad esempio:

L'array viene calcolato con un crivello di Eratostene modificato: durante l'elaborazione del numero primo , il valore spf[j] = p viene assegnato a ogni multiplo del numero , per il quale non è ancora stato impostato.

Avendo l'array , si può calcolare la parte libera da quadrati di ogni numero . Sia il minimo divisore primo del numero (spf[i] = p). Consideriamo due casi:

sf[i] = sf[i / p^2]

Ad esempio:

  1. sf[12] = sf[3], poiché spf[12] = 2 e è divisibile per 2^2;

  2. = , poiché spf[45] = 3 e è divisibile per 3^2;

sf[i] = sf[i / p] \cdot p

Ad esempio:

  1. sf[30] = sf[15] \cdot 2, poiché spf[30] = 2 e non è divisibile per 2^2;

  2. sf[18] = sf[9] \cdot 2, poiché spf[18] = 2 e non è divisibile per 2^2;

Esempio

Calcoliamo la risposta per n = 10.

i

scomposizione in fattori

parte libera da quadrati

1 * 2^2

2 * 3

2 * 2^2

1 * 3^2

2 * 5

Raggruppiamo i numeri nell'array in base a .

cnt[1] = 3: (1, 4, 9)

cnt[6] = 1: (6)

cnt[2] = 2: (2, 8)

cnt[7] = 1: (7)

cnt[3] = 1: (3)

cnt[8] = 0: ()

cnt[4] = 0: ()

cnt[9] = 0: ()

cnt[5] = 1: (5)

cnt[10] = 1: (10)

La risposta è uguale a

\frac{cnt[1] \cdot (cnt[1] - 1)}{2} + \frac{cnt[2] \cdot (cnt[2] - 1)}{2} = \frac{3 \cdot 2}{2} + \frac{2 \cdot 1}{2} = 3 + 1 = 4

Implementazione dell'algoritmo

Dichiariamo le costanti e gli array.

#define MAXN 1000000
#define MOD 1000000007
int spf[MAXN + 1];     // divisore primo minimo del numero
int sf[MAXN + 1];      // parti libere da quadrati del numero
int cnt[MAXN + 1];     // quantità di numeri con un dato sf

Leggiamo il valore di input .

scanf("%d", &n);

Applicando il metodo del crivello di Eratostene, riempiamo l'array :

Inizialmente supponiamo che ogni numero sia divisibile per se stesso. Ma questo è temporaneo.

for (i = 1; i <= n; i++) spf[i] = i;

Nella variabile scorriamo i numeri da a \sqrt{n}.

for (i = 2; i * i <= n; i++)
{
  if (spf[i] == i)
  {

Se il numero è primo, nella variabile scorriamo i numeri i^2, i^2 + i, i^2 + 2i, ... . Tutti questi numeri hanno il divisore primo (poiché spf[i] = i). Se spf[j] = j, allora aggiorniamo il divisore primo minimo per il numero .

    for (j = i * i; j <= n; j += i)
      if (spf[j] == j) spf[j] = i;
  }
}

Per ogni numero calcoliamo la sua parte libera da quadrati. Il risultato lo inseriamo in .

sf[1] = 1;
for (i = 2; i <= n; i++)
{

La variabile contiene il minimo divisore primo del numero .

  p = spf[i];
  x = i / p;

Se è divisibile per p^2, allora sf[i] = sf[i / p^2].

  if (x % p == 0)
    sf[i] = sf[x / p];

Se non è divisibile per p^2 (ma è divisibile per ), allora sf[i] = sf[i / p] \cdot p.

  else
    sf[i] = sf[x] * p;
}

Raggruppiamo i numeri in base alla loro parte libera da quadrati.

for (i = 1; i <= n; i++)
  cnt[sf[i]]++;

Calcoliamo la risposta — il numero di coppie cercato.

res = 0;
for (i = 1; i <= n; i++)
  if (cnt[i] >= 2)
    res = (res + cnt[i] * (cnt[i] - 1) / 2) % MOD;

Stampiamo la risposta.

printf("%lld\n", res);