Description
给你一个序列,问有多少个区间[l,r]满足l~r的每一个数01随意排列异或和为0。
Sample Input
3
6 7 14
Sample Output
2
你可以发现一个性质:
一个区间内的数总和为偶数,且总和大于最大的数乘二就肯定满足条件,根据这个进行分治即可。
好像还是可以直接DP的,设f[i][j]为枚举到第i个数有j个1未配对的情况,转移即可。
我写的是分治,因为我想出了性质。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
LL read() {
LL s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
int S[2][2][200];
LL ans, a[310000];
LL n, bin[61];
int lowbit(int x) {return x & -x;}
void change(int x, int c, int opt, int hh) {for(int i = x; i <= 130; i += lowbit(i)) S[hh][opt][i] += c;}
int getsum(int x, int opt, int hh) {int sum = 0; for(int i = x; i; i -= lowbit(i)) sum += S[hh][opt][i]; return sum;}
void clear(int x, int opt, int hh) {for(int i = x; i <= 130; i += lowbit(i)) S[hh][opt][i] = 0;}
void solve(int l, int r) {
if(l == r) return ;
int mid = (l + r) / 2;
solve(l, mid),
solve(mid + 1, r);
int sum = 0, maxx = 0;
for(int i = mid; i >= l; i--) {
sum += a[i], maxx = _max(maxx, a[i]);
int o = _max(0, maxx * 2 - sum) + 1;
change(o, 1, sum % 2, 0);
}
int maxx1 = 0, sum1 = 0, sum2 = 0, maxx2 = 0;
int tp = mid + 1;
for(int i = mid + 1; i <= r; i++) {
maxx1 = _max(maxx1, a[i]), sum1 += a[i];
while(tp > l && maxx1 > a[tp - 1]) {
sum2 += a[--tp];
maxx2 = _max(maxx2, a[tp]);
int o = _max(0, maxx2 * 2 - sum2) + 1;
change(130 - _min(sum2, 129), 1, sum2 % 2, 1);
change(o, -1, sum2 % 2, 0);
} ans += getsum(130 - _max(0, maxx1 * 2 - sum1), sum1 % 2, 1);
ans += getsum(_min(sum1, 129) + 1, sum1 % 2, 0);
} sum = maxx = 0;
for(int i = mid; i >= l; i--) {
sum += a[i], maxx = _max(maxx, a[i]);
int o = _max(0, maxx * 2 - sum) + 1;
clear(o, sum % 2, 0), clear(130 - _min(sum, 129), sum % 2, 1);
}
}
int main() {
n = read();
bin[0] = 1LL; for(int i = 1; i <= 60; i++) bin[i] = bin[i - 1] * 2LL;
for(int i = 1; i <= n; i++) {
LL x = read();
for(int j = 60; j >= 0; j--) if(x >= bin[j]){
a[i]++, x -= bin[j];
}
} ans = 0; solve(1, n);
printf("%lld\n", ans);
return 0;
}