Numero di multiset in modo tale che ciascun numero sia compreso tra 1 e


11

Il mio problema. Dato , voglio contare il numero di multinsiemi valida S . Una multiset SnSS è valida se

  • La somma degli elementi di èS , en
  • Ogni numero da a n può essere espresso in modo univoco come somma di alcuni degli elementi di S1nS .

Esempio. Ad esempio, se allora sono validi { 1 , 1 , 1 , 1 , 1 } , { 1 , 2 , 2 } , { 1 , 1 , 3 } .n=5{1,1,1,1,1},{1,2,2},{1,1,3}

Tuttavia, non è valido perché 2 può essere formato da { 1 , 1 } e { 2 } (ovvero, 2 può essere espresso come 2 = 1 + 1 e 2 = 2 ) , quindi la seconda condizione non regge. Allo stesso modo 3 può essere formato da { 2 , 1 } e { 1 , 1 , 1 } .S={1,1,1,2}{1,1}{2}2=1+12=2{2,1}{1,1,1}

} non è valido perché tutti i numeri da 1 a 5 possono essere creati in modo univoco, ma la somma degli elementi di S non è 5S={1,2,415S5 .


Ho provato a trovare un buon algoritmo per questo problema per un po 'di tempo ma non riesco a risolverlo. Viene da codechef . Ho visto alcune delle soluzioni presentate ma non riuscivo ancora a ottenere la logica per risolvere il problema. NOTA: il limite di tempo per la domanda è di 10 secondi e n<109

Per un multiset userò la notazione Un i < un j se i < j , il che significa un i verifica c iS={(a1,c1),(a2,c2)...} ai<aji<jaici tempi in multinsieme S.

Fino ad ora ho tratto alcune conclusioni

  • Il primo elemento del multiset ordinato richiesto dovrebbe essere 1
  • Sia essere un insieme seguendo le due proprietà quindi r < k a r + 1 = a r  oppure  ( r i = 0 a i ) + 1S={1,a2ak}|a1a2akr<k  ar+1=ar or (i=0rai)+1
  • Sia , dove un mi sta verificando c i tempi, segue le proprietà richieste quindi dalla conclusione sopra possiamo dire che i un i | n + 1 eS={(1,c1),(a2,c2)(ak,ck)}|a1a2akaicii ai|n+1 se j > i . Prova: a i + 1 = ( a i c i + a i - 1 ) + 1 a i | a i + 1ai|ajj>i
    ai+1=(aici+ai1)+1ai|ai+1
  • Ora considera cioè tutti i i numeri successivi dopo 1 saranno un multiplo di d . Quindi lascia che f ( n )S={1,11d1,d,dd,dm1,dm1dm1,dm2,dm2dm2,}df(n)essere il conteggio di tale multiset possibile quindi dove sto sommando tutto il numero possibile di1s(=d-1). In altri terminif(n-1)=g(n)=d| n,dng(d)f(n)=d|n+1,d1f(n(d1)d)1s=d1f(n1)=g(n)=d|n,dng(d)

Alla fine il mio problema si riduce a questo: trova in modo efficiente in modo che non superi il limite di tempo.g(n)


2
Hai verificato se è opportuno chiedere ad altre persone di pubblicare pubblicamente soluzioni e algoritmi per problemi di pratica? Le FAQ di Codechef sembrano aspettarsi che le soluzioni non vengano pubblicate pubblicamente (ad eccezione di alcuni problemi di base). Pubblicare una soluzione qui "rovinerebbe" i problemi di pratica per gli altri, o è considerato OK? Non ho familiarità con le norme e l'etichetta della comunità Codechef.
DW

Non ho trovato nulla correlato a non pubblicare domande di dominio pubblico nelle faq e questa limitazione riguarda i problemi di contestazione in corso e non quelli di pratica.
Justice League,

1
@DW Non credo che a loro dispiacerebbe se discutiamo di problemi che non provengono da concorsi in corso.
Ravi Upadhyay,

1
Stai cercando il numero di partizioni del numero di input. Ti suggerisco di fare qualche ricerca usando questa parola d'ordine.
Raffaello

2
@Raphael, sono d'accordo, il poster dovrebbe leggere queste tecniche. Non è esattamente lo stesso problema - la prima condizione del poster richiede che si tratti di una partizione, ma la seconda condizione impone ulteriori restrizioni (per la modifica univoca ) - ma potrebbe essere possibile applicare le stesse tecniche utilizzate per contare il numero delle partizioni, con alcune modifiche per far fronte al requisito aggiuntivo.
DW

Risposte:


2

Ecco cosa sta facendo la soluzione più veloce . Sta effettivamente calcolando la tua funzione Dato n , lo fattorizziamo (vedi sotto) e quindi calcoliamo tutti i fattori (vedi sotto) f 1 , , f m in un ordine tale che f i | f j implica i j (proprietà P). Ora calcoliamo g secondo la formula andando oltre i fattori nell'ordine dato. La proprietà P assicura che quando calcoliamo g ( d ) , abbiamo già calcolato g ( e ) per tutti i fattori non banali

g(n)=dnd<ng(d),g(1)=1.
nf1,,fmfi|fjijgg(d)g(e)edi d . C'è anche un'ottimizzazione (vedi sotto).

Più in dettaglio, esaminiamo i fattori in ordine e, per ogni fattore , troviamo tutti i suoi fattori non banali controllando quale di f 1 , ... , f i - 1 divide f i .fif1,,fi1fi

Factoring: preelaborazione: facciamo un elenco di tutti i numeri primi inferiori a usando il setaccio Eratosthenes. Dato n , usiamo semplicemente la divisione di prova.109n

Generazione di tutti i fattori: questo viene fatto in modo ricorsivo. Supponiamo che . Si corre t nested loop l 1{ 0 , ... , k 1 } , ... , l t{ 0 , ... , k t } , e l'uscita p l 1 1p l t t . Puoi provare la proprietà P per induzione.n=p1k1ptkttl1{0,,k1},,lt{0,,kt}p1l1ptlt

Ottimizzazione: poiché il programma è eseguito su più input, possiamo usare la memoization per risparmiare tempo su diversi input. Memorizziamo solo piccoli valori (fino a 105 ) e questo ci consente di memorizzare tutti i valori memorizzati in un array. L'array è inizializzato con zero e quindi possiamo dire quali valori sono già noti (poiché tutti i valori calcolati sono positivi).


Se la scomposizione in fattori primi di è p k 1 1 , , p k t t , allora f ( n ) dipende solo da ( k 1 , , k t ) , e di fatto solo dalla versione ordinata di questo vettore . Ogni numero inferiore a 10 9 ha al massimo 29 fattori primi (con ripetizione) e poiché p ( 29 ) = 4565 , sembra possibile calcolare fn+1p1k1,,ptktf(n)(k1,,kt)10929p(29)=4565f(o meglio ) per tutti, ricorsivamente. Questa soluzione potrebbe essere più veloce se ci fossero molti input diversi; così com'è, ci sono al massimo 10 .g10

È anche possibile che questa funzione, mappando le partizioni sulla corrispondente , abbia una forma analitica esplicita. Ad esempio, g ( p k ) = 2 k - 1 , g ( p 1p t ) è dato da A000670 e g ( p 2 1 p 2p t ) è dato da A005649 o A172109 .gg(pk)=2k1g(p1pt)g(p12p2pt)


1

OK, quindi hai una relazione di ricorrenza per (vedi la fine della tua domanda).g()

A questo punto sembra che un approccio naturale sarebbe scrivere l'algoritmo ricorsivo per calcolare e applicare la memoizzazione in modo da non calcolare g ( i ) più di una volta. In altre parole, quando si calcola g ( i ) , lo si memorizza in una tabella hash che mappa i g ( i ) ; se hai bisogno di conoscere di nuovo g ( i ) in futuro, puoi cercarlo nella tabella hash.g(n)g(i)g(i)ig(i)g(i)

nnn109

g(1),g(2),g(3),g(4),g(5),


0

Ecco un suggerimento per iniziare. Applicare algoritmi di programmazione dinamica standard per enumerare il set di partizioni di un numero intero e aggiungere un po 'di logica per verificare quale di queste consente la modifica univoca controllando iterativamente tutte le somme, apportando modifiche e verificando l'univocità.

Si1inSi

SnS

P(n)P(1),P(2),,P(n)P(n+1)


Ecco un approccio che probabilmente sarà migliore.

SnTSTn

xSSTxSSTn

SA[1|S|,1n]A[i,j]jiSiSSS={s1,s2,,sk}s1s2skA[i,j]A[1i1,1j1]A[i,j]=A[i1,j]A[i1,jsi]j>siA[i,j]=A[i1,j]S

TSSTnSnTn+1,n+2,,nTAA[1|T|,1n]A[|T|,n+1],A[|T|,n+2],,A[|T|,n]TS

Snn20P[120]P[5]SP[n]Sn

P[n]P[1]{1}nSP[n]TSnTTP[n]n20

Questo dovrebbe essere abbastanza fattibile. In bocca al lupo! Divertiti! Lavorare attraverso i dettagli sarà un buon esercizio di apprendimento nella programmazione dinamica.


n
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.