D: Xor Sum 2 - AtCoder Regular Contest 098

排他的論理和が総和以下っぽい。詳しく説明する。

x, y, z \in \mathbb{Z}_+とする。 まずx\oplus y \leq x+yが成り立つ。更に「x \lt y ならば x\oplus z \lt y+z」も成り立つ。

部分文字列の左端lを固定してみる。このときr=lならば明らかに条件を満たす。

A[l]⊕A[l+1]⊕...⊕A[r] < A[l]+A[l+1]+...+A[r]

が成り立つと仮定する。このとき、先のxorの性質により

A[l]⊕A[l+1]⊕...⊕A[r]⊕A[r+1] < A[l]+A[l+1]+...+A[r]+A[r+1]

が成り立つ。 よって右端をいくら伸ばしても常に総和のほうが大きい。 つまりl<=r<=Nについて順に

等しい、等しい、等しい、等しい、総和のほうが大きい、総和のほうが大きい

のように等しい場合は左側に、値が異なる場合は右側に寄るので、値が等しくなる場合を二分探索する。

実行時間はO(Nlog(N))

int N;
cin >> N;
vector<ll> S(N + 1), T(N + 1);
rep(a, N) {
    int b;
    cin >> b;
    S[a + 1] = S[a] ^ b;
    T[a + 1] = T[a] + b;
}
ll re = 0;
rep(l, N) {
    int ok = l + 1, ng = N + 1;
    while (ng - ok > 1) {
        int r = (ok + ng) / 2;
        ll s = S[r] ^ S[l];
        ll t = T[r] - T[l];
        (s == t ? ok : ng) = r;
    }
    re += ok - l;
}
cout << re << endl;