Sie erhalten einen großen Bereich [a, b], in dem 'a' und 'b' normalerweise zwischen 1 und 4.000.000.000 einschließlich liegen können. Sie müssen das XOR aller Zahlen im angegebenen Bereich ermitteln.
Dieses Problem wurde in TopCoder SRM verwendet. Ich habe eine der im Spiel eingereichten Lösungen gesehen und kann nicht herausfinden, wie sie funktioniert.
Könnte jemand helfen, die Gewinnerlösung zu erklären:
long long f(long long a) {
long long res[] = {a,1,a+1,0};
return res[a%4];
}
long long getXor(long long a, long long b) {
return f(b)^f(a-1);
}
Hier getXor()
ist die eigentliche Funktion zum Berechnen des xor aller Zahlen im übergebenen Bereich [a, b] und "f ()" ist eine Hilfsfunktion.
a<=0
oder fürb<0
.long long
ist ein vorzeichenbehafteter Typ, alsox%4
negativ (oder 0) für negative Eingänge . Vielleicht möchten Sieunsigned long long
und / odera & 3
das Array indizieren?Antworten:
Dies ist eine ziemlich clevere Lösung - sie nutzt die Tatsache aus, dass die laufenden XORs ein Ergebnismuster aufweisen. Die
f()
Funktion berechnet den XOR-Gesamtlauf aus [0, a]. In dieser Tabelle finden Sie 4-Bit-Zahlen:Dabei ist die erste Spalte die Binärdarstellung und dann das Dezimalergebnis und seine Beziehung zu seinem Index (a) in der XOR-Liste. Dies geschieht, weil alle oberen Bits alle 4 abgebrochen werden und die unteren zwei Bits alle 4 durchlaufen. So gelangen Sie zu dieser kleinen Nachschlagetabelle.
Betrachten Sie nun einen allgemeinen Bereich von [a, b]. Wir können verwenden
f()
, um das XOR für [0, a-1] und [0, b] zu finden. Da jeder Wert, den XOR mit sich selbst hat, Null ist, löscht dasf(a-1)
Just alle Werte im XOR-Lauf kleiner alsa
und lässt Sie mit dem XOR des Bereichs [a, b] zurück.quelle
a
gibt es 2, nicht 0.Neben der großartigen Antwort von FatalError
return f(b)^f(a-1);
könnte die Zeile besser erklärt werden. Kurz gesagt, weil XOR diese wunderbaren Eigenschaften hat:Hier ist beides in Aktion:
So was:
Addieren und multiplizieren sind zwei Beispiele für andere assoziative / kommutative Operatoren, die sich jedoch nicht umkehren. Ok, warum sind diese Eigenschaften wichtig? Ein einfacher Weg besteht darin, es auf das zu erweitern, was es wirklich ist, und dann können Sie diese Eigenschaften bei der Arbeit sehen.
Definieren wir zunächst, was wir wollen, und nennen es n:
Wenn es hilft, denken Sie an XOR (^), als wäre es ein Add.
Definieren wir auch die Funktion:
b
ist größer alsa
, also können wir auch Folgendes sagen, indem wir sicher ein paar zusätzliche Klammern einfügen (was wir können, weil es assoziativ ist):Was vereinfacht zu:
Als nächstes verwenden wir diese Umkehreigenschaft und Kommutivität, um uns die magische Linie zu geben:
Wenn Sie XOR als Add betrachtet haben, hätten Sie dort einen Subtrahieren vorgenommen. XOR ist zu XOR, was addieren ist zu subtrahieren!
Wie komme ich selbst darauf?
Denken Sie an die Eigenschaften logischer Operatoren. Arbeiten Sie mit ihnen fast wie Addieren oder Multiplizieren, wenn es hilft. Es fühlt sich ungewöhnlich an, dass und (&), xor (^) und oder (|) assoziativ sind, aber sie sind!
Führen Sie zuerst die naive Implementierung durch, suchen Sie in der Ausgabe nach Mustern und suchen Sie dann nach Regeln, die bestätigen, dass das Muster wahr ist. Vereinfachen Sie Ihre Implementierung noch weiter und wiederholen Sie den Vorgang. Dies ist wahrscheinlich der Weg, den der ursprüngliche Ersteller eingeschlagen hat, was durch die Tatsache hervorgehoben wird, dass er nicht vollständig optimal ist (dh eine switch-Anweisung anstelle eines Arrays verwenden).
quelle
Ich fand heraus, dass der folgende Code auch wie die in der Frage angegebene Lösung funktioniert.
Vielleicht ist dies wenig optimiert, aber es ist genau das, was ich durch das Beobachten von Wiederholungen erhalten habe, wie in der akzeptierten Antwort angegeben.
Ich möchte den mathematischen Beweis hinter dem gegebenen Code kennen / verstehen, wie in der Antwort von @Luke Briggs erklärt
Hier ist dieser JAVA-Code
quelle
Ich habe das Problem mit der Rekursion gelöst. Ich teile den Datensatz einfach für jede Iteration in einen fast gleichen Teil.
Lassen Sie mich Ihre Gedanken über die Lösung wissen. Freut mich über Verbesserungsrückmeldungen. Die vorgeschlagene Lösung berechnet das XOR in der Komplexität 0 (log N).
Danke dir
quelle
Um XOR von 0 bis N zu unterstützen, musste der angegebene Code wie folgt geändert werden:
quelle