La combinatoria del transistor


20

Il videogioco Transistor presenta un sistema di abilità molto interessante. Raccogli 16 "Funzioni" che puoi utilizzare in 16 slot diversi. La cosa interessante è che ci sono 3 tipi di slot e ogni funzione si comporta in modo diverso a seconda dello slot in cui lo usi:

  • Ci sono 4 slot passivi .
  • Ci sono 4 slot attivi .
  • Ogni slot attivo ha 2 slot di aggiornamento .

Vogliamo capire quante diverse abilità ci danno.

Tuttavia, alcune combinazioni sono equivalenti. In particolare, all'interno di ciascuno di quei gruppi di slot, la posizione specifica di una funzione non ha importanza. D'altra parte, l'effetto di una funzione in uno Slot di aggiornamento non dipendono dalla funzione specifica utilizzata nel genitore slot attivo.

Pertanto, utilizzando cifre esadecimali per sostituire le funzioni, le seguenti combinazioni sono tutte equivalenti:

Passive Slots:    0     1     2     3
Active Slots:     4     5     6     7
Upgrade Slots:   8 9   A B   C D   E F

Passive Slots:    2     0     1     3    # Permutation of passive slots.
Active Slots:     4     5     6     7
Upgrade Slots:   8 9   A B   C D   E F

Passive Slots:    0     1     2     3
Active Slots:     5     6     4     7    # Permutation of active slots together
Upgrade Slots:   A B   C D   8 9   E F   # with their upgrade slots.

Passive Slots:    0     1     2     3
Active Slots:     4     5     6     7
Upgrade Slots:   8 9   B A   C D   F E   # Permutation within upgrade slots.

così come qualsiasi combinazione di questi riarrangiamenti. Si noti che nel terzo caso gli slot di aggiornamento sono stati scambiati con gli slot attivi per mantenere lo stesso effetto complessivo.

D'altra parte, le seguenti combinazioni sono tutte diverse dal set sopra:

Passive Slots:    4     5     6     7    # Passive slots swapped
Active Slots:     0     1     2     3    # with active slots.
Upgrade Slots:   8 9   A B   C D   E F

Passive Slots:    0     1     2     3
Active Slots:     5     4     6     7    # Permutation of active slots without
Upgrade Slots:   8 9   A B   C D   E F   # changing upgrade slots.

Passive Slots:    0     1     2     3
Active Slots:     4     5     6     7
Upgrade Slots:   8 A   9 B   C D   E F   # Permutation between different upgrade slots.

Secondo il mio conteggio che ti dà 2.270.268.000 possibili combinazioni (funzionalmente distinte), supponendo che vengano utilizzate tutte le funzioni.

Se hai meno di 16 funzioni a tua disposizione, alcuni degli slot rimarranno vuoti. Tuttavia, si noti che non è possibile posizionare una funzione in uno slot di aggiornamento se lo slot attivo principale è vuoto.

La sfida

Devi determinare il numero di possibili configurazioni in base a quante funzioni hai. Inoltre, generalizzerò leggermente il problema rendendo variabile il numero di slot, al fine di prevenire banali soluzioni di hardcoding.

Scrivi un programma o una funzione che, dati due numeri interi positivi M ≥ 1e 1 ≤ N ≤ 4M, determina il numero di set di abilità possibili (funzionalmente distinti) assumendo che Nfunzioni esattamente diverse vengano utilizzate per riempire il maggior numero possibile di slot Mpassivi, Mattivi e di 2Maggiornamento.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

Il codice deve essere in grado di gestire qualsiasi input fino a M = 8un minuto compreso su un computer desktop ragionevole. C'è un certo margine di manovra in questo, ma dovrebbe escludere soluzioni di forza bruta. In linea di principio non dovrebbe essere un problema risolvere uno di questi input in meno di un secondo.

Questo è il codice golf, vince la risposta più breve (in byte).

Casi test

Ogni caso di test è nel modulo M N => Result.

1 1 => 2
1 2 => 4
1 3 => 9
1 4 => 12
2 1 => 2
2 2 => 6
2 3 => 21
2 4 => 78
2 5 => 270
2 6 => 810
2 7 => 1890
2 8 => 2520
3 1 => 2
3 2 => 6
3 3 => 23
3 4 => 98
3 5 => 460
3 6 => 2210
3 7 => 10290
3 8 => 44520
3 9 => 168840
3 10 => 529200
3 11 => 1247400
3 12 => 1663200
4 1 => 2
4 2 => 6
4 3 => 23
4 4 => 100
4 5 => 490
4 6 => 2630
4 7 => 14875
4 8 => 86030
4 9 => 490140
4 10 => 2652300
4 11 => 13236300
4 12 => 59043600
4 13 => 227026800
4 14 => 718918200
4 15 => 1702701000
4 16 => 2270268000
5 1 => 2
5 2 => 6
5 3 => 23
5 4 => 100
5 5 => 492
5 6 => 2672
5 7 => 15694
5 8 => 98406
5 9 => 644868
5 10 => 4306932
5 11 => 28544670
5 12 => 182702520
5 13 => 1101620520
5 14 => 6122156040
5 15 => 30739428720
5 16 => 136670133600
5 17 => 524885961600
5 18 => 1667284819200
5 19 => 3959801445600
5 20 => 5279735260800
6 1 => 2
6 2 => 6
6 3 => 23
6 4 => 100
6 5 => 492
6 6 => 2674
6 7 => 15750
6 8 => 99862
6 9 => 674016
6 10 => 4787412
6 11 => 35304654
6 12 => 265314588
6 13 => 1989295308
6 14 => 14559228684
6 15 => 101830348620
6 16 => 667943115840
6 17 => 4042651092480
6 18 => 22264427465280
6 19 => 110258471363040
6 20 => 484855688116800
6 21 => 1854067032417600
6 22 => 5894824418683200
6 23 => 14025616720315200
6 24 => 18700822293753600
7 1 => 2
7 2 => 6
7 3 => 23
7 4 => 100
7 5 => 492
7 6 => 2674
7 7 => 15752
7 8 => 99934
7 9 => 676428
7 10 => 4849212
7 11 => 36601554
7 12 => 288486132
7 13 => 2349550632
7 14 => 19504692636
7 15 => 162272450340
7 16 => 1328431104000
7 17 => 10507447510560
7 18 => 78942848624640
7 19 => 554967220167360
7 20 => 3604592589998400
7 21 => 21411337810262400
7 22 => 115428212139240000
7 23 => 561247297649438400
7 24 => 2439121536313862400
7 25 => 9283622495827680000
7 26 => 29520583763711040000
7 27 => 70328449554723360000
7 28 => 93771266072964480000
8 1 => 2
8 2 => 6
8 3 => 23
8 4 => 100
8 5 => 492
8 6 => 2674
8 7 => 15752
8 8 => 99936
8 9 => 676518
8 10 => 4852992
8 11 => 36722169
8 12 => 291621462
8 13 => 2418755196
8 14 => 20834571186
8 15 => 184894557705
8 16 => 1672561326150
8 17 => 15217247948760
8 18 => 137122338089880
8 19 => 1204392465876600
8 20 => 10153538495100000
8 21 => 81007229522419200
8 22 => 604136189949692400
8 23 => 4168645459350372000
8 24 => 26403795950145213600
8 25 => 152700324078982680000
8 26 => 803784718213396920000
8 27 => 3838761204861983400000
8 28 => 16503742828841748480000
8 29 => 62545434470667308160000
8 30 => 198853691115980300400000
8 31 => 474189571122722254800000
8 32 => 632252761496963006400000

Questi sono tutti gli input che il tuo codice deve gestire entro un minuto (ciascuno), ma in linea di principio dovrebbe funzionare per input più grandi. È possibile utilizzare alcuni dei seguenti M = 10casi di test per verificare che:

10 1 => 2
10 2 => 6
10 3 => 23
10 4 => 100
10 5 => 492
10 6 => 2674
10 7 => 15752
10 8 => 99936
10 9 => 676520
10 10 => 4853104
10 11 => 36727966
10 12 => 291849866
10 13 => 2426074222
10 14 => 21033972388
10 15 => 189645995396
10 16 => 1773525588406
10 17 => 17155884420532
10 18 => 171073929494468
10 19 => 1750412561088334
10 20 => 18258387148774916
10 21 => 192475976310317700
10 22 => 2028834600633220380
10 23 => 21127206177119902860
10 24 => 214639961631544809360
10 25 => 2101478398293813739200
10 26 => 19602967930531817832000
10 27 => 172444768103233181556000
10 28 => 1417975382888905296456000
10 29 => 10820259026484304813416000
10 30 => 76213534343700480310584000
10 31 => 493916052421168703366040000
10 32 => 2941900199368102067135040000
10 33 => 16113144277547868007416960000
10 34 => 81222252655277786422930560000
10 35 => 376309102059179385262246080000
10 36 => 1589579966324953534441910400000
10 37 => 5981477408861097281112374400000
10 38 => 19005991357166148698688124800000
10 39 => 45381652832417130566255318400000
10 40 => 60508870443222840755007091200000

È obbligatorio riempire il maggior numero possibile di slot?
feersum

7
Immagino che dovrei aspettare la mia turn()prima che io help()ti get()load()ping()void()spark()crash()
dia

@feersum Sì, tutte le Nfunzioni sono in uso.
Martin Ender,

Risposte:


18

CJam (56 byte)

q~4@:Nm*:$_&{:+1$\-N),&},f{1$1$:+-\0-:(_e`0f=+++:m!:/}:+

Demo online

NnKmnMN

X0XMN-XN!X!(N-X)!N-XM3

λ0,λ1,...,λKλ0λ1(N-X)!λ0!λ1!...λK!λio=λjμio3 2 2 1μ3=1μ2=2μ1=1λioλio

Quindi per ogni partizione il numero di distribuzioni di funzioni è

N!X!(λ0-1)!...(λK-1)!μ1!μ2!μ3!

Il codice sopra calcola le partizioni usando lo stesso approccio di Dennis (è ovvio e breve, anche se non molto scalabile) e quindi elabora ciascuna partizione in una matrice simile alla [N X λ_0-1 ... λ_k-1 μ_1 μ_2 μ_3]quale può sollevare la funzione fattoriale e quindi piegare la divisione.


9

CJam, 74 67 byte

q~4@:Mm*:$L|{:+W$\-M),&},f{0-:F1@@{_m!\I-:Nm!/I(m!/*N}fI;Fm!Fe=/}:+

Ho verificato tutti i casi di test sul mio computer desktop utilizzando l' interprete Java . Questa operazione ha richiesto 2,2 secondi per 1 ≤ M ≤ 8 e 3,5 minuti per M = 10 .

Prova questo violino nell'interprete CJam o verifica i primi 84 casi di test contemporaneamente .

Idea

In linea di principio, possiamo riempire ogni slot attivo e i relativi slot di aggiornamento con 0 , 1 , 2 o 3 funzioni. Per gli slot 4M in totale, prendiamo tutti i vettori V di {0, 1, 2, 3} M e filtriamo quelli per i quali somma (V)> N (più funzioni negli slot non passivi rispetto alle funzioni totali disponibili) o somma ( V) + M <N (slot passivi insufficienti per funzioni non attive). Ordiniamo e dedupliamo tutti i vettori mantenuti, poiché l'ordine delle famiglie di slot non è importante.

Con le funzioni N e le funzioni V = (x 1 ,…, x M ) nelle parti non passive delle famiglie di slot, calcoliamo il numero di combinazioni come segue:

  1. Se x 1 = 0 , esiste una sola possibilità per quella famiglia di slot.

    Se x 1 = 1 , ci sono N possibilità, poiché abbiamo N funzioni e la funzione deve andare nello slot attivo.

    Se x 1 = 2 , dobbiamo posizionare una funzione nello slot attivo e un'altra in uno slot di aggiornamento (non importa quale). Sono disponibili N scelte per lo slot attivo e N-1 rimanenti per lo slot di aggiornamento, per un totale di N (N-1) combinazioni.

    Se x 1 = 3 , ci sono N scelte per lo slot attivo, N - 1 scelte rimanenti per il primo slot di aggiornamento e N - 2 per il secondo slot di aggiornamento. Poiché gli slot di aggiornamento non hanno alcun ordine, questo conta ogni combinazione due volte, quindi ci sono N (N - 1) (N - 2) combinazioni uniche.

    In ogni caso, ci sono N! / ((N - x 1 )! × (x 1 - 1)! Combinazioni per questa famiglia.

  2. Abbiamo utilizzato x 1 funzioni, quindi imposta N: = N - x 1 e ripeti il ​​passaggio 1 per x 2 , quindi x 3 , ecc.

  3. Se V contiene duplicati, il prodotto dei risultati precedenti avrà contato più volte tutte le combinazioni. Per ogni elemento univoco di V , se si verifica r volte in V , ci sono r! modi equivalenti per organizzare queste famiglie di slot, quindi il risultato dall'alto deve essere diviso per r! .

  4. Il risultato finale è il numero di combinazioni uniche per quel V .

Per calcolare il numero totale di combinazioni uniche, tutto ciò che resta da fare è quello di calcolare la somma dei risultati per ciascun V .

Codice

q~        e# Read an evaluate all input from STDIN. Pushes M and N.
4@:M      e# Push 4, rotate the M, and formally save it in M.
m*        e# Push {0, 1, 2, 3}^M.
:$        e# Sort each vector.
L|        e# Perform set union with the empty list (deduplicates).
{         e# For each sorted vector:
  :+      e#   Compute the sum of its coordinates.
  W$\-    e#   Subtract the sum from N (bottom of the stack).
  M),&    e#   Push [0 ... M] and intersect.
},        e# If the intersection was not empty, keep the vector.
f{        e# For each kept vector, push N and V; then:
  0-:F    e#   Save the non-zero elements of V in F.
  1@@     e#   Push 1 (accumulator), and rotate N and F on top of it.
  {       e#   For each I in F:
    _m!   e#     Push I and push factorial(I).
    \I-:N e#     Subtract I from N and update N.
    m!/   e#     Divide factorial(N) (original N) by factorial(N) (updated N).
    I(m!/ e#     Divide the quotient by factorial(I - 1).
    *     e#    Multiply the accumulator by the resulting quotient.
    N     e#    Push N for the next iteration.
  }fI     e#
  ;       e#   Pop N.
  Fm!     e#   Push all non-unique permutations of F.
  Fe=     e#   Count the number of times F appears.
  /       e#   Divide the accumulator by the result.
}         e#
:+        e# Add all resulting quotients.
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.