Il meno comune non divisore


11

SdSxS, dx

Indica n=|S|e C=max(S) . Considera la funzione F(x)= il numero primo minimo che non divide x . È facile vedere che F(x)logx . E per una serie S , lasciate F(S)= il minimo primo che non divide alcun elemento di S . Abbiamo un limite superiore

F(S)F(lcm(S))F(Cn)nlogC.

Pertanto un semplice algoritmo a forza bruta, che enumera tutti i numeri da 1 a nlogC e verifica se non divide alcun elemento di S , è polinomiale e ha complessità temporale O(n2logC) .

L'altro modo per risolvere il problema è calcolare tutti i fattori per ogni elemento di S e usarli nell'algoritmo a forza bruta per verificare se x è una risposta nel tempo O(1) . Questo algoritmo ha una complessità temporale O(nmin(C,nlogC)+nlogC) e utilizza la memoria O(nlogC) , perché non è necessario calcolare e fattori negozio più grande di nlogC . Per i piccoli n e C funziona meglio.

Nel dettaglio, l'algoritmo è costituito da due parti:

  1. Costruisci un set S^ composto da tutti i fattori di tutti gli elementi di S , ovvero

    xS fnlogC, (fxfS^)
    Questo può essere fatto nella memoria O(nmin(C,nlogC)) e O(nlogC) . (Da dove viene? Per qualsiasi elemento di S , possiamo fattorizzarlo utilizzando la fattorizzazione di prova con tutti i numeri fino a C o tutti i numeri primi fino a nlogC , a seconda di quale sia il più piccolo; quindi ogni elemento di S può essere preso in considerazione nel tempo O(min(C,nlogC)) .)
  2. Trova il numero minimo . Questo passaggio richiede , se si verifica se può essere eseguito in .dS^O(|S^|)=O(nlogC)xS^O(1)

Ho due domande a cui sono interessato:

  1. Esiste un algoritmo più veloce per risolvere il problema?
  2. Per dato e , come possiamo costruire un insieme con il massimo divisore minimo comune?nCS

1. Con "precompute" intendevo prima di iniziare l'algoritmo di forza bruta. 2. La complessità del factoring è davvero subexponential, vedere la definiton di . C
SkyterX,

@DW al punto 2, la complessità del factoring è sub-esponenziale sulla lunghezza della stringa di bit che rappresenta il numero, ma SkyterX afferma correttamente che è , cioè proporzionale alla radice quadrata della dimensione di il numero. O(C)
Lieuwe Vinkhuijzen,

@LieuweVinkhuijzen, Non mi sembra giusto. La complessità del factoring usando GNFS sarà qualcosa di simile a , che è significativamente inferiore a O ( O(exp{1.9(logC)1/3(loglogC)2/3}). Vedien.wikipedia.org/wiki/…. O(C)
DW

L'affermazione secondo cui il secondo metodo funziona meglio "per piccoli e C " non è del tutto corretta. Funziona meglio solo se n nC. Quindindeve essere grande perché il secondo metodo funzioni meglio (non piccolo). nC/log(C)n
DW

@DW Hai ragione, non ero a conoscenza della complessità del GNFS.
Lieuwe Vinkhuijzen,

Risposte:


6

È possibile migliorare il secondo algoritmo utilizzando algoritmi migliori per la fattorizzazione a numeri interi.

Esistono due algoritmi per la fattorizzazione dei numeri interi che sono rilevanti qui:

  • GNFS può fattorizzare un numero intero con tempo di esecuzione O ( L C [ 0,33 , 1,92 ] ) .CO(LC[0.33,1.92])

  • L'ECM può trovare un fattore (se presente) con tempo di esecuzione O ( L n log C [ 0,5 , 1,41 ] ) ; trovare tutti i fattori richiederà O ( log C / log ( n log C ) ) il tempo (che è relativamente piccolo rispetto al tempo di esecuzione di ECM).nlogCO(LnlogC[0.5,1.41])O(logC/log(nlogC))

Qui .Ln[α,c]=exp{c(logn)α(loglogn)1α}

È un'espressione piuttosto orribile per il tempo di esecuzione, ma il fatto importante è che questo è più veloce dei metodi che hai citato. In particolare, è asintoticamente molto più piccola di LC[0.33,1.92] , cioè GNFS è molto più veloce di provare tutti i possibili fattoriC . AncheL n log C [0.5,1.41]è asintoticamente molto più piccolo dinlogC, vale a dire, ECM è molto più veloce che cercare tutti i possibili fattorinlogC.CLnlogC[0.5,1.41]nlogCnlogC

Quindi, il tempo di esecuzione totale per questo metodo è approssimativamente , e questo è asintoticamente migliore del tuo primo metodo e asintoticamente migliore di il tuo secondo metodo. Non so se sia possibile fare ancora meglio.O~(nmin(LC[0.33,1.92],LnlogC[0.5,1.41]))


Credo, che qualsiasi algoritmo veloce per questo problema deve includere un qualche tipo di fattorizzazione di set di ingresso . Esaminerò quegli algoritmi di fattorizzazione, ma c'è ancora un problema nel testarli correttamente, che solleva un secondo problema di cui ho parlato sulla costruzione dell'insieme S con la risposta massima. SS
SkyterX,

L'ECM trova un fattore nel tempo che dai. Se tutti i fattori di un numero sono ≤ n log C, è necessario ripetere l'algoritmo, fino a registrare i tempi C / log (n log C).
gnasher729,

3

Il non divisore meno comune può essere grande quanto N log C, ma se i numeri N vengono distribuiti casualmente, il non divisore meno comune è probabilmente molto più piccolo, probabilmente molto meno di N. Costruirò tabelle di cui i numeri primi sono divisori di cui numeri.

Per ogni numero primo p abbiamo un indice che significa che tutti i numeri fino a quell'indice sono stati esaminati per divisibilità per p, e abbiamo un elenco di tutti quei numeri che erano divisibili per.kp

Quindi per d = 2, 3, 4, ... proviamo a trovare un numero divisibile per d, o mostriamo che non ce n'è nessuno. Prendiamo il più grande fattore primo p di d. Quindi controlliamo tutti i numeri che erano divisibili per p se sono anche divisibili per d. Se non ne viene trovato nessuno, controlliamo ulteriori numeri con indici> per divisibilità per p, aggiornando k p e l'elenco dei numeri divisibili per p, e verificando se ogni numero è divisibile per d.kpkp

Per verificare se esiste un numero divisibile per p, controlliamo la media dei numeri p. Successivamente, se controlliamo se esiste un numero divisibile per 2p, c'è una probabilità del 50% che dobbiamo controllare solo un numero (quello che è divisibile per p) e una probabilità del 50% per controllare in media 2p più numeri. Trovare un numero divisibile per 3p è molto probabilmente veloce e così via, e non controlliamo mai più di N numeri per divisibilità per p, perché ci sono solo N numeri.

Mi auguro che questo funziona con circa controlli divisibilità.N2/logN

PS. Quanto sarebbe grande il risultato per i numeri casuali?

Supponiamo che io abbia N numeri casuali. La probabilità che uno dei numeri N sia divisibile per d è 1 - (1 - 1 / d) ^ N. Suppongo che la probabilità che ciascuno dei numeri 1 ≤ d ≤ k sia un fattore di uno dei numeri casuali viene calcolato moltiplicando queste probabilità (Ok, è un po 'complicato, perché queste probabilità probabilmente non sono del tutto indipendenti).

Con questa ipotesi, con N = 1000, c'è una probabilità del 50% che uno dei numeri 1..244 non divida alcun numero e uno su un miliardo che ogni numero fino a 507 divide uno dei numeri. Con N = 10.000 c'è una probabilità del 50% che uno dei numeri 1..1726 non divida alcun numero e uno su un miliardo che ogni numero fino a 2979 divide uno dei numeri.

Suggerirei che per N input casuali, la dimensione del risultato è un po 'più grande di N / ln N; forse qualcosa come N / ln N * (ln ln N) ^ 2. Ecco perché:

La probabilità che almeno uno degli N numeri casuali è divisibile per un d casuale è . Se d è intorno a N, allora 1 - ( 1 - 1 / d ) N è circa 1 - exp (-1) ≈ 0.6321. Questo è per un singolo divisore; è probabile che ciascuno dei diversi numeri d ≈ N sia un divisore di almeno uno dei numeri N che è piuttosto sottile, quindi il massimo d sarà significativamente più piccolo di N.1(11/d)N1(11/d)N

Se d << N, quindi .1(11/d)N1exp(N/d)

Se d ≈ N / ln N poi .1exp(N/d)1exp(lnN)=11/N

Aggiungeremo queste probabilità per circa N / ln N valori d, ma per la maggior parte d il risultato sarà significativamente più grande, quindi la più grande d sarà in qualche modo più grande di N / ln N ma significativamente più piccola di N.

PS. Trovare un numero divisibile per d:

Selezioniamo il più grande fattore primo p di d, quindi esaminiamo prima i numeri che erano già noti per essere divisibili per p. Dì d = kp. Quindi in media controlliamo solo k numeri che sono divisibili per p mentre controlliamo questo particolare d, e controlliamo al massimo tutti i valori N per la divisibilità per p complessivo, per tutti i d divisibili per p. In realtà, molto probabilmente controlliamo meno di N valori per la maggior parte dei numeri primi p, perché dopo aver controllato tutti i valori N l'algoritmo probabilmente finisce. Quindi, se il risultato è R, allora mi aspetto che meno di N valori vengano divisi per ciascun numero primo minore di R. Supponendo R ≤ N, si tratta di N ^ 2 / log N checks.

PS. Esecuzione di alcuni test

Ho eseguito questo algoritmo alcune volte con N = 1.000.000 di numeri casuali> 0. Il non divisore meno comune era tra 68.000 e 128.000 con la stragrande maggioranza delle corse tra 100.000 e 120.000. Il numero di divisioni era compreso tra 520 milioni e 1800 milioni, che è molto inferiore a (N / ln N) ^ 2; la maggior parte dei casi utilizzava tra 1000 e 1500 milioni di divisioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.