原题连接
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; }