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ステートメントを使用します)。