<-- home

AtCoder ABC 121 D

https://atcoder.jp/contests/abc121/tasks/abc121_d

「解説」と違う方針で解いたのでメモ。

を求めるとき、を2進数で表したときの桁目は、排他的論理和が各桁ごとに独立に計算できることから、それぞれの桁目から計算できる。 そこで、桁目が0であるものがn個, 1であるものがm個とすると、排他的論理和が交換法則を満たすことに着目して、桁目はとなる。

であるから、

となる。

0から順に2進数で書いてみると、

0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1 0 0 1
0 0 0 0 0 0 0 0 1 0 1 0
0 0 0 0 0 0 0 0 1 0 1 1
0 0 0 0 0 0 0 0 1 1 0 0
0 0 0 0 0 0 0 0 1 1 0 1
0 0 0 0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 1 0 0 0 0

となるので、桁目は、0が個、1がというパターンが繰り返されることがわかる。したがって、0からある2進数桁目に1が何個あるかはで求められる。これを用いれば、桁目に1が何個あるかもで求められる。 したがって、の0桁目から順に求めて、O(max(Aの桁数, Bの桁数))で答えが計算できる。

#define N_DIGIT 40
i64 A, B;

int main() {
    cin >> A >> B;
    if (A == B) {
        cout << A << endl;
        return 0;
    }

    i64 ans = 0;
    i64 p = 1;
    auto f = [&](i64 x, i64 p, i64 n) {
        // [0, x) のn桁目に1が何個あるか
        i64 k = x / p;
        if ((x >> n) & 1) {
            return (k / 2) * p + x % p;
        } else {
            return (k / 2) * p;
        }
    };

    REP(i, N_DIGIT + 1) {
        i64 n_one = f(B + 1, p, i) - f(A, p, i);
        ans += (n_one % 2) * p;
        p *= 2;
    }
    cout << ans << endl;

    return 0;
}