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:
- Es ist assoziativ - Platzieren Sie Klammern, wo immer Sie möchten
- Es ist kommutativ - das heißt, Sie können die Operatoren bewegen (sie können "pendeln").
Hier ist beides in Aktion:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
So was:
a ^ b = c
c ^ a = b
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:
n = (a ^ a+1 ^ a+2 .. ^ b)
Wenn es hilft, denken Sie an XOR (^), als wäre es ein Add.
Definieren wir auch die Funktion:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
ist größer als a
, 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):
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
Was vereinfacht zu:
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
Als nächstes verwenden wir diese Umkehreigenschaft und Kommutivität, um uns die magische Linie zu geben:
n = f(b) ^ f(a-1)
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).