2012-09-22 16 views

risposta

21

Se la somma di due numeri è divisibile per k dipende solo dal resto modulo modulo k.

Quindi se k è ragionevolmente piccolo, è sufficiente contare quanti numeri hanno ogni resto possibile e calcolare il numero di coppie da quello. Supponendo k > 0 e tutti i numeri interi non negativi

unsigned long long combinations(unsigned k, unsigned long long *arr, unsigned n) { 
    unsigned long long counts[k] = {0}; 
    unsigned i; 
    for(i = 0; i < n; ++i) { 
     ++counts[arr[i]%k]; 
    } 
    // number of pairs where both are divisible by k 
    unsigned long long combs = counts[0]*(counts[0]-1)/2; 
    for(i = 1; i < (k+1)/2; ++i) { 
     combs += counts[i]*counts[k-i]; 
    } 
    if (k == 2*i) { 
     combs += counts[i]*(counts[i] - 1)/2; 
    } 
    return combs; 
} 

fa il lavoro in O(n+k) passi. Se n è piccolo e k molto grande, l'algoritmo ingenuo è migliore.

+0

Mi hai battuto :) Comunque, vuoi usare count [], non arr [] dove stai facendo i pettini, e devi considerare i conteggi [0] – rici

+0

Great! Tempo lineare .. è quello che stavo cercando .. Grazie! – user1599964

+0

@rici Grazie per l'heads-up. 'counts [0]' è usato nell'inizializzazione di 'petts', non l'ho dimenticato (ma ho avuto un altro errore di battitura,' k-1' invece di 'k-i'). –

3

In aggiunta a ciò che dice Daniel Fischer, se k è molto grande, è possibile ordinare i numeri mod k, e quindi percorrere la lista ordinata da entrambe le estremità (dopo aver affrontato i valori 0 mod k) verso il centro (k/2 mod k). Quello è O (n log n), che è meglio di O (n^2), assumendo che il tuo algoritmo ingenuo sia davvero ingenuo.

+0

My Naive ha coinvolto la ricerca binaria ... Quindi sarebbe anche O (n log n) ma sì, la tua versione è un miglioramento ... poiché riguarda solo O (n log n) per l'ordinamento .. e trova in lineare O (n) tempo piuttosto che O (n log n) utilizzando la ricerca binaria. Grazie ! +1 :) – user1599964

+0

È possibile utilizzare una tabella hash invece di ordinamento/ricerca binaria per arrivare a O (n). –

+0

@KeithRandall, si, puoi provarlo. Mi aspetterei che la mia soluzione sarebbe di solito più veloce, perché il suo ciclo interno è molto veloce, ma potrei sbagliarmi. Se vuoi provarlo, ti suggerirei un buon hash per un intero mod k sarebbe il numero intero k mod p dove p è un primo vicino a n. Ciò mantiene lo storage su O (n), che è competitivo con search-and-scan. (Usare il numero intero k stesso ovviamente non garantisce alcuna collisione, ma poi hai ridotto il problema al binsort di Daniel, e in questo caso lo abbiamo scartato perché i raccoglitori occupano troppa memoria.) – rici

Problemi correlati