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,a2⋯ak}|a1≤a2⋯≤ak∀r<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)}|a1≤a2⋯≤akaici∀i 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+ai−1)+1⇒ai|ai+1
  • Ora considera cioè tutti i i numeri successivi dopo 1 saranno un multiplo di d . Quindi lascia che f ( n )S={1,1⋯1⏟d−1,d,d⋯d,dm1,dm1⋯dm1,dm2,dm2⋯dm2,⋯}df(n)essere il conteggio di tale multiset possibile quindi dove sto sommando tutto il numero possibile di1′s(=d-1). In altri terminif(n-1)=g(n)=∑d| n,d≠ng(d)f(n)=∑d|n+1,d≠1f(n−(d−1)d)1′s=d−1f(n−1)=g(n)=∑d|n,d≠ng(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)=∑d∣nd<ng(d),g(1)=1.
nf1,…,fmfi|fji≤jgg(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,…,fi−1fi

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 1 ⋯ p l t t . Puoi provare la proprietà P per induzione.n=p1k1⋯ptkttl1∈{0,…,k1},…,lt∈{0,…,kt}p1l1⋯ptlt

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 1 … p t ) è dato da A000670 e g ( p 2 1 p 2 … p t ) è dato da A005649 o A172109 .gg(pk)=2k−1g(p1…pt)g(p12p2…pt)


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)i↦g(i)g(i)

nnn≤109

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

Si1≤i≤nSi

SnS

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


Ecco un approccio che probabilmente sarà migliore.

SnTSTn′

xSSTxSSTn

SA[1…|S|,1…n]A[i,j]jiSiSSS={s1,s2,…,sk}s1≤s2≤⋯≤skA[i,j]A[1…i−1,1…j−1]A[i,j]=A[i−1,j]∨A[i−1,j−si]j>siA[i,j]=A[i−1,j]S

TSSTnSn′Tn+1,n+2,…,n′TAA[1…|T|,1…n′]A[|T|,n+1],A[|T|,n+2],…,A[|T|,n′]TS

Snn≤20P[1…20]P[5]SP[n]Sn

P[n]P[1]{1}nS∈P[n]TSn′TTP[n′]n′≤20

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.