FatalErrorのすばらしい答えに加えて、この行return f(b)^f(a-1);
はよりよく説明できます。つまり、XORには次のすばらしい特性があるからです。
- それは連想的です -好きな場所にブラケットを配置します
- それは可換的です -それはあなたがオペレーターを動かすことができることを意味します(彼らは「通勤する」ことができます)
両方が動作しています:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
このような:
a ^ b = c
c ^ a = b
加算と乗算は、他の連想/可換演算子の2つの例ですが、逆になりません。では、なぜこれらのプロパティが重要なのでしょうか。まあ、単純なルートは、それを実際の状態に拡張することです。そうすれば、これらのプロパティが機能しているのがわかります。
まず、必要なものを定義してnと呼びます。
n = (a ^ a+1 ^ a+2 .. ^ b)
役立つ場合は、XOR(^)をアドのように考えてください。
関数も定義しましょう:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
がより大きいa
ので、いくつかの余分なブラケットを安全にドロップすることで(これは結合的であるため可能です)、次のように言うこともできます。
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
これは次のように簡素化されます。
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
次に、その反転プロパティとコミュニティを使用して、魔法の線を作成します。
n = f(b) ^ f(a-1)
XORを加算のように考えている場合は、そこに減算をドロップします。XORはXORであり、加算は減算です。
これを自分でどうやって思いつくのですか?
論理演算子のプロパティを覚えておいてください。効果がある場合は、加算または乗算のようにそれらを使用します。and(&)、xor(^)、or(|)が結合的であるのは珍しく感じますが、それらは結合的です!
単純な実装を最初に実行し、出力でパターンを探してから、パターンが真であることを確認するルールの検索を開始します。実装をさらに簡素化して繰り返します。これはおそらく、元の作成者がたどった経路であり、完全に最適ではないという事実(つまり、配列ではなくswitchステートメントを使用する)によって強調されています。