Eine binäre Zeichenfolge ist eine Zeichenfolge, die nur Zeichen enthält, die aus 01 stammen . Eine ausgeglichene Binärzeichenfolge ist eine Binärzeichenfolge, die genau so viele 0 s wie 1 s enthält.
Sie erhalten eine positive Ganzzahl n und eine beliebige Anzahl von Masken, von denen jede 2n Zeichen lang ist und nur Zeichen enthält, die aus 012 stammen . Eine binäre Zeichenfolge und eine Maske stimmen überein, wenn sie dieselbe Länge haben und an jeder Stelle, an der die Maske keine 2 hat, mit dem Zeichen übereinstimmen . ZB die Maske 011.022 Matches die Binärketten 011000 , 011001 , 011010 , 011011 .
Wenn Sie n und die Masken als Eingabe angeben (durch Zeilenumbrüche getrennt), müssen Sie die Anzahl der unterschiedlichen ausgeglichenen Binärzeichenfolgen ausgeben, die mit einer oder mehreren der Masken übereinstimmen.
Beispiele
Eingang
3
111222
000112
122020
122210
102120
Argumentation
- Die einzige ausgeglichene binäre Zeichenfolge, die mit 111222 übereinstimmt, ist 111000 .
- Die einzige ausgeglichene binäre Zeichenfolge, die mit 000112 übereinstimmt, ist 000111 .
- Die ausgeglichenen binären Zeichenfolgen, die mit 122020 übereinstimmen, sind 111000 (bereits gezählt), 110010 und 101010 .
- Die ausgeglichenen binären Zeichenfolgen, die mit 122210 übereinstimmen, sind 110010 (bereits gezählt), 101010 (bereits gezählt) und 100110 .
- Die ausgeglichenen binären Zeichenfolgen, die mit 102120 übereinstimmen, sind 101100 und 100110 (bereits gezählt).
So sollte die Ausgabe sein
6
Eingang
10
22222222222222222222
Argumentation
- Es gibt 20 wähle 10 ausgeglichene Binärzeichenfolgen der Länge 20.
Ausgabe
184756
Gewinner
Der Gewinner ist derjenige, der den Wettbewerbseingang am schnellsten berechnet und ihn natürlich genauso behandelt wie jeden anderen Input. (Ich verwende einen bestimmten Code, um einen eindeutigen Gewinner zu haben und Fälle zu vermeiden, in denen unterschiedliche Eingaben unterschiedliche Gewinner ergeben würden. Wenn Sie einen besseren Weg finden, um den schnellsten Code zu finden, sagen Sie es mir.)
Wettbewerbsbeitrag
quelle
Antworten:
C.
Wenn Sie nicht unter Linux arbeiten oder anderweitig Probleme beim Kompilieren haben, sollten Sie wahrscheinlich den Timing-Code (
clock_gettime
) entfernen .Beispielfälle:
(Die Zeiten gelten für eine i7-4770K-CPU mit 4,1 GHz.) Seien Sie vorsichtig und
testcase-hard
verwenden Sie etwa 3-4 GB Speicher.Dies ist so ziemlich eine Implementierung der Einschluss-Ausschluss-Methode, die blutorange entwickelt hat, aber so, dass sie Schnittpunkte beliebiger Tiefe handhabt.
Der geschriebene Code verbringt viel Zeit mit der Speicherzuweisung und wird noch schneller, sobald ich die Speicherverwaltung optimiere.Ich habe mich bei ungefähr 25% rasiert
testcase-hard
, aber die Leistung des Originals (testcase-long
) ist ziemlich unverändert, da dort nicht viel Speicher zugewiesen wird. Ich werde noch ein bisschen mehr tunen, bevor ich es nenne: Ich denke, ich könnte auch eine Verbesserung von 25% bis 50% erzielentestcase-long
.Mathematica
Als ich bemerkte, dass dies ein # Sat-Problem war, wurde mir klar, dass ich das integrierte Mathematica verwenden konnte
SatisfiabilityCount
:Ausgabe:
Das sind 298.208.861.472 Masken in 1,3 Sekunden (i7-3517U bei 1,9 GHz), einschließlich der Zeit, die für das Herunterladen des Testfalls vom Pastebin aufgewendet wurde.
quelle
testcase-hard
kann sehr schnell abgeschlossen werden, wenn Ihr Code nach Masken sucht, die kombiniert werden können. Wenn Ihr Code dies tut, löschen Sie jede zweite Zeile (so/^2*02*$/
bleiben nur die Fälle übrig). Ich denke nicht, dass dieser Fall optimiert werden kann.rubinrot, ziemlich schnell, aber es kommt auf die Eingabe an
Beschleunigen Sie jetzt um den Faktor 2 bis 2,5, indem Sie von Zeichenfolgen zu Ganzzahlen wechseln.
Verwendungszweck:
Z.B.
Die Anzahl der Übereinstimmungen für eine einzelne Maske wird leicht durch den Binomialkoeffizienten berechnet. So
122020
braucht zum Beispiel 32
s gefüllt, 10
und 21
. Daher gibt esnCr(3,2)=nCr(3,1)=3!/(2!*1!)=3
verschiedene binäre Zeichenfolgen, die zu dieser Maske passen.Ein Schnittpunkt zwischen n Masken m_1, m_2, ... m_n ist eine Maske q, so dass eine Binärzeichenfolge s nur dann mit q übereinstimmt, wenn sie mit allen Masken m_i übereinstimmt.
Wenn wir zwei Masken m_1 und m_2 nehmen, kann der Schnittpunkt leicht berechnet werden. Setzen Sie einfach m_1 [i] = m_2 [i], wenn m_1 [i] == 2. Der Schnittpunkt zwischen
122020
und111222
ist111020
:Die zwei einzelnen Masken werden durch 3 + 1 = 4 Zeichenfolgen abgeglichen, die Schnittmaske wird durch eine Zeichenfolge abgeglichen, daher gibt es 3 + 1-1 = 3 eindeutige Zeichenfolgen, die mit einer oder beiden Masken übereinstimmen.
Ich werde N (m_1, m_2, ...) nennen, die Anzahl der Zeichenfolgen, die mit allen m_i übereinstimmen. Unter Anwendung der gleichen Logik wie oben können wir die Anzahl der eindeutigen Zeichenfolgen berechnen, die mit mindestens einer Maske übereinstimmen, die durch das Einschlussausschlussprinzip gegeben ist, und siehe auch unten wie folgt:
Es gibt viele, viele, viele Kombinationen von etwa 30 von 200 Masken.
Diese Lösung geht also davon aus, dass nicht viele Schnittpunkte höherer Ordnung der Eingabemasken existieren, d. H. Die meisten n-Tupel mit n> 2 Masken haben keine gemeinsamen Übereinstimmungen.
Verwenden Sie den Code hier, der Code bei ideone ist möglicherweise veraltet.
Ich habe eine Funktion hinzugefügt
remove_duplicates
, mit der die Eingabe vorverarbeitet und Masken gelöscht werden könnenm_i
, sodass alle übereinstimmenden Zeichenfolgen auch mit einer anderen Maske übereinstimmenm_j
. Für die aktuelle Eingabe dauert dies tatsächlich länger, da es keine solchen Masken gibt (oder nicht viele). Daher wird die Funktion im folgenden Code noch nicht auf die Daten angewendet.Code:
Dies wird als Einschluss-Ausschluss-Prinzip bezeichnet, aber bevor mich jemand darauf hingewiesen hatte, hatte ich meinen eigenen Beweis. Etwas selbst zu tun fühlt sich aber großartig an.
Betrachten wir den Fall von 2 Masken, rufen Sie dann
0
und1
zuerst an. Wir nehmen jede ausgeglichene Binärzeichenfolge und klassifizieren sie nach den übereinstimmenden Masken.c0
diejenigen , die Anzahl der , die nur Maske entsprechen0
,c1
die nunber von denen , die nur entsprechen1
,c01
diejenigen , die Spiel - Maske0
und1
.Sei
s0
die Zahlensumme der Anzahl der Übereinstimmungen für jede Maske (sie können sich überlappen). Seis1
die Summe der Übereinstimmungen für jedes Maskenpaar (2-Kombinationen). Seis_i
die Summe der Anzahl der Übereinstimmungen für jede (i + 1) Maskenkombination. Die Anzahl der Übereinstimmungen von n-Masken ist die Anzahl der Binärzeichenfolgen, die allen Masken entsprechen.Wenn es n Masken gibt, ist die gewünschte Ausgabe die Summe aller
c
, dh.c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1)
. Was das Programm berechnet, ist die alternierende Summe allers
, dh.s = s_0-s_1+s_2-+...+-s_(n-1)
. Das möchten wir beweisens==c
.n = 1 ist offensichtlich. Betrachte n = 2. Das Zählen aller Übereinstimmungen von Masken
0
gibtc0+c01
(die Anzahl der Zeichenfolgen, die nur mit 0 übereinstimmen + die mit beiden übereinstimmen0
und1
), das Zählen aller Übereinstimmungen von1
gibtc1+c02
. Wir können dies wie folgt veranschaulichen:Per Definition
s0 = c0 + c1 + c12
.s1
ist die Summe der Übereinstimmungen jeder 2-Kombination von[0,1]
, dh. alle uniqyec_ij
s. Denken Sie daranc01=c10
.Also
s=c
für n = 2.Betrachten Sie nun n = 3.
Also
s=c
für n = 3.c__i
repräsentiert das allerc
s mit (i + 1) Indizes, zBc__1 = c01
für n = 2 undc__1 = c01 + c02 + c12
für n == 3.Für n = 4 beginnt ein Muster aufzutauchen:
Also
s==c
für n = 4.Im Allgemeinen erhalten wir Binomialkoeffizienten wie diese (↓ ist i, → ist j):
Um dies zu sehen, bedenken Sie, dass es für einige
i
und folgendej
gibt:Da dies verwirrend klingen mag, ist hier die Definition eines Beispiels. Für i = 1, j = 2, n = 4 sieht es so aus (vgl. Oben):
Hier ist also x = 6 (01, 02, 03, 12, 13, 23), y = 2 (zwei c mit drei Indizes für jede Kombination), z = 4 (c012, c013, c023, c123).
Insgesamt gibt es
x*y
Koeffizientenc
mit (j + 1) -Indizes, und es gibtz
verschiedene, so dass jedesx*y/z
Mal auftritt , was wir den Koeffizienten nennenk_ij
. Durch einfache Algebra erhalten wirk_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1)
.Der Index ist also gegeben durch
k_ij = nCr(j+1,i+1)
Wenn Sie sich an alle Definitionen erinnern, müssen wir nur zeigen, dass die alternierende Summe jeder Spalte 1 ergibt.Die alternierende Summe
s0 - s1 + s2 - s3 +- ... +- s(n-1)
kann somit ausgedrückt werden als:Also
s=c
für alle n = 1,2,3, ...quelle
0011 < 2211
,0022 < 0222
. Ich denke, das macht die Gruppen nicht größer als2*n
, obwohl es im schlimmsten Fall immer noch zu groß ist.unifying two masks
der Begriffunion
für mich Sinn macht und ich xan so definieren, aber du hast Recht, im Interesse des gegenseitigen Verständnisses habe ich mich geärgert. @ Agawa001 Kannst du genauer sein? Wenn Sie eine gute Idee haben, dies zu beschleunigen, können Sie auch Ideen aus dieser Antwort für Ihr Programm / Ihre Antwort verwenden. Im Moment ist es schnell genug für den großen Testfall, und wenn es mit mehreren Threads erstellt wird, sollte es <0,1 s dauern, was unter jeder aussagekräftigen Messung / Vergleich liegt, sodass für schwierigere Testfälle erforderlich sind.C.
Viel Glück, dass der große Input dazu kommt - es wird wahrscheinlich die ganze Nacht dauern, bis ca. 60 ^ 30 Permutationen! Vielleicht ist ein Datensatz mittlerer Größe eine gute Idee?
quelle