Thêm vào câu trả lời tuyệt vời của FatalError, dòng return f(b)^f(a-1);
này có thể được giải thích tốt hơn. Tóm lại, đó là vì XOR có những đặc tính tuyệt vời sau:
- Nó có tính liên kết - Đặt dấu ngoặc ở bất cứ đâu bạn muốn
- Nó có tính chất giao hoán - có nghĩa là bạn có thể di chuyển các toán tử xung quanh (chúng có thể "đi làm")
Đây là cả hai hoạt động:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
Như thế này:
a ^ b = c
c ^ a = b
Cộng và nhân là hai ví dụ về các toán tử kết hợp / giao hoán khác, nhưng chúng không tự đảo ngược. Ok, vậy, tại sao những thuộc tính này lại quan trọng? Chà, một lộ trình đơn giản là mở rộng nó thành những gì thực sự là, và sau đó bạn có thể thấy những thuộc tính này hoạt động.
Đầu tiên, hãy xác định những gì chúng ta muốn và gọi nó là n:
n = (a ^ a+1 ^ a+2 .. ^ b)
Nếu nó hữu ích, hãy nghĩ về XOR (^) như thể nó là một phép cộng.
Hãy cũng xác định hàm:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
lớn hơn a
, vì vậy, chỉ cần thêm vào một vài dấu ngoặc đơn một cách an toàn (mà chúng ta có thể làm được vì nó có tính liên kết), chúng ta cũng có thể nói điều này:
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
Đơn giản hóa thành:
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
Tiếp theo, chúng tôi sử dụng thuộc tính đảo ngược và tính phổ biến đó để cung cấp cho chúng tôi đường kỳ diệu:
n = f(b) ^ f(a-1)
Nếu bạn đang nghĩ về XOR giống như một phép cộng, bạn sẽ bỏ qua một số trừ ở đó. XOR là XOR những gì cộng là để trừ!
Làm cách nào để tôi tự nghĩ ra điều này?
Ghi nhớ các thuộc tính của toán tử logic. Làm việc với chúng gần giống như một phép cộng hoặc nhân nếu nó hữu ích. Có cảm giác không bình thường khi và (&), xor (^) và hoặc (|) là liên kết, nhưng chúng là vậy!
Trước tiên, hãy chạy quá trình triển khai ngây thơ, tìm kiếm các mẫu trong đầu ra, sau đó bắt đầu tìm các quy tắc xác nhận mẫu là đúng. Đơn giản hóa việc triển khai của bạn hơn nữa và lặp lại. Đây có lẽ là lộ trình mà người tạo ban đầu đã thực hiện, nổi bật bởi thực tế là nó không hoàn toàn tối ưu (tức là sử dụng câu lệnh switch thay vì một mảng).