Dodając do świetnej odpowiedzi FatalError, kwestię tę return f(b)^f(a-1);
można wyjaśnić lepiej. Krótko mówiąc, to dlatego, że XOR ma te wspaniałe właściwości:
- Jest asocjacyjny - umieść nawiasy w dowolnym miejscu
- Jest przemienny - oznacza to, że możesz przemieszczać operatorów (mogą „dojeżdżać”)
Oto oba w akcji:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
Lubię to:
a ^ b = c
c ^ a = b
Dodawanie i mnożenie to dwa przykłady innych operatorów asocjacyjnych / przemiennych, ale one same się nie odwracają. Ok, więc dlaczego te właściwości są ważne? Cóż, prostą drogą jest rozszerzenie tego na to, czym naprawdę jest, a następnie możesz zobaczyć te właściwości w działaniu.
Najpierw zdefiniujmy, czego chcemy i nazwijmy to:
n = (a ^ a+1 ^ a+2 .. ^ b)
Jeśli to pomoże, pomyśl o XOR (^) tak, jakby to był dodatek.
Zdefiniujmy też funkcję:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
jest większe niż a
, więc po prostu bezpiecznie upuszczając kilka dodatkowych nawiasów (co możemy, ponieważ jest asocjacyjne), możemy również powiedzieć to:
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
Co upraszcza:
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
Następnie używamy tej właściwości odwrócenia i przemienności, aby uzyskać magiczną linię:
n = f(b) ^ f(a-1)
Jeśli myślałeś o XOR jak o dodaniu, zostawiłbyś tam odejmowanie. XOR jest dla XOR tym, czym dodawanie jest odejmowaniem!
Jak mam to wymyślić?
Zapamiętaj właściwości operatorów logicznych. Pracuj z nimi prawie jak dodawanie lub mnożenie, jeśli to pomaga. Wydaje się niezwykłe, że i (&), xor (^) i lub (|) są skojarzone, ale tak jest!
Najpierw uruchom naiwną implementację, poszukaj wzorców w danych wyjściowych, a następnie zacznij znajdować reguły, które potwierdzają, że wzorzec jest prawdziwy. Jeszcze bardziej uprość wdrażanie i powtórz. Prawdopodobnie jest to droga, którą obrał pierwotny twórca, podkreślona faktem, że nie jest ona całkowicie optymalna (tj. Użyj instrukcji switch zamiast tablicy).