原題連接
ios
首先注意到「二進制重排」,實際上也就是說,\(a_i\)是多少不重要,有用的信息是它自己有多少個1。
spa
而後,\([L, r]\)內異或和爲0,能夠認爲是這個區間內的1可以相互抵消。那麼這個區間內1的個數必定是偶數個。
code
咱們考慮1的個數爲偶數個的狀況下,如何纔會出現不能相互抵消的狀況。這種「特殊狀況」其實就是存在一個數,它的1的數量比其餘的數加起來都多。除了這種狀況外,其餘狀況下均可以所有抵消。
rem
那麼咱們能夠預處理出 \(pre[i]\),表明\(1 - i\)中有多少個1,而後從頭開始掃描,同時記錄兩個變量,一是\(1 - i - 1\)中有多少個\(pre[j]\)爲奇數,二是多少個爲偶數。而後咱們在\(i\)處時,給答案加上表明與\(pre[i]\)相同奇偶性的變量便可。
get
在掃描的同時,咱們須要減去答案中的全部符合「特殊狀況」的\([l, i]\)區間數量。可是咱們並不須要從1開始枚舉,由於每一個二進制數最多不超過63個1,因此事實上咱們的枚舉範圍爲\([i - 63, i]\)便可,剩下的長度大於63的區間必定不會符合「特殊狀況」。
string
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <map> using namespace std; const int N = 300000; long long abss(long long a) { if (a < 0) { a = -a; } return a; } long long n; long long xx; long long aa[N + 5] = {0}, su[N + 5]; long long mm[105] = {0}; int main() { mm[0] = 1; scanf("%lld", &n); long long ans = 0; su[0] = 0; for (int i = 1; i <= n; ++i) { scanf("%lld", &xx); while (xx) { if (xx & 1) { ++aa[i]; } xx >>= 1; } su[i] = su[i - 1] + aa[i]; } long long l[2] = {1, 0}; aa[0] = 0; for (int i = 1; i <= n; ++i) { int bitt = su[i] & 1; ans += l[bitt]; long long mx = aa[i]; long long rem = 0; for (int j = i - 1; j >= 0 && j >= i - 63; --j) { if ((su[i] - su[j]) % 2 == 0 && rem < mx) { --ans; } if (mx < aa[j]) { rem += mx; mx = aa[j]; } else { rem += aa[j];; } } ++l[bitt];; } printf("%lld", ans);; return 0; }