題意:給n個數,每個數的二進制1都可以隨意的換位置,問區間異或爲0的有多少個
思路:該問題可以轉化爲他的充要條件:
1.區間1的個數爲偶數
2.區間最大值不超過區間和的一半;
偶數區間個數可以用cnt[i][2]記錄以1開始,1~i中偶數和奇數區間個數,
那麼偶數區間就是假如現在前綴是偶數,那就加cnt偶數,反之加奇數。
因爲偶數=偶-偶/奇減奇
對於不符合的,因爲數是60位左右,所以最大值不超過60,假如有一個數是60那麼其他數至少爲1,這樣往前 遍歷60來次
就足矣。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int cnt[N][2], num[N];
int main(){
int n;
//cout<<__builtin_popcount(1000000000000ll)<<endl;
scanf("%d", &n);
for(int i=1; i<=n; i++){
ll t;
scanf("%I64d", &t);
//num[i]=__builtin_popcount(t);
while(t){
if(t&1) num[i]++;
t>>=1;
}
//printf("%d ", num[i]);
}
//puts("");
cnt[0][0]=1;
ll ans=0, sum=0;
for(int i=1; i<=n; i++){
int s=0, mx=0;
sum+=num[i];
if(sum&1)
ans+=cnt[i-1][1];
else
ans+=cnt[i-1][0];
cnt[i][1]=cnt[i-1][1]+(sum&1);
cnt[i][0]=cnt[i-1][0]+(sum%2==0);
for(int j=i; j>0&&i-j+1<=63; j--){
s+=num[j];
mx=max(mx, num[j]);
if(s%2==0 && mx>s-mx) ans--;
}
}
printf("%I64d\n", ans);
return 0;
}