AtCoder, ABC121: D. XOR World
非常に大きな数(になりうる)2数 が与えられます.
このときに, を求める問題です.
ここで, とは のように定義される関数です(ここで, は排他的論理和を表します).
が小さな値であり が非常に大きな数である場合,愚直に繰り返し計算をすると現実的な時間で計算ができません.
ここで, をじっと眺めると(嘘: 私は解説を読みました), は のように分解できることがわかります.
これについては解説を読んだだけではわからなかったのですが,実際に書き下してみると「なるほど!」となります.
これにより, を効率的に計算できれば良いということがわかりました.
では,これを求めるアルゴリズムを考えましょう.
連続する2数 の排他的論理和は,
となります(実際に2進数で試してみてください).
実際にはどちらか一方を利用するととで問題は解けます.
ここでは, が偶数の時の結果を利用します.
は2数 を用いて のように表せます.
は以下のように定義できます.
考え方としては以下ようになります.
- ] の数列を [t, t+1] でくくり,くくれた部分を とみなし, を考える
- が綺麗にくくり出せない場合,前の処理で得られた数と との排他的論理和をとる
コードは↓
#include <iostream> # define rep(i, n) for (int i = 0; i < (int)(n); i++) using namespace std; long long f(long long a) { long long t, s; if (((a+1)/2)%2 == 0) t = 0; else t = 1; if ((a+1)%2 == 0) s = 0; else s = a; return t ^ s; } int main() { long long a, b; cin >> a >> b; cout << (f(a-1) ^ f(b)) << endl; return 0; }