题意
给一个长度为(n)的位数为(k)的整数数列(a),一次操作可将任意(a_i)取反,问经过任意次操作后最多有多少个区间异或和不为(0)
分析
求出前缀异或和,区间异或和为(0)的区间数转化为求有多少对前缀异或和相等,然后用总区间数减一下,
对一个(a_i)取反等同于对这个位置的前缀异或和取反,所以每个位置的前缀异或和有两种,贪心取当前值出现次数最小的一种,
总区间数为(n*(n+1)/2) ,对于每个非(0)数字减去(C(x,2)),(x)为这个数的出现次数,对于(0)要减去(C(x+1,2)),可以在数列中加一个(0)消除这个影响
Code
#include<bits/stdc++.h>
#define fi first
#define se second
#define bug cout<<"--------------"<<endl
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
const double eps=1e-6;
const int inf=1e9;
const ll llf=1e18;
const int mod=1e9+7;
const int maxn=2e5+10;
int n,k;
int a[maxn];
int b[maxn];
map<int,int>f;
int col(int x){
return ((1<<k)-1-x);
}
vector<int>q;
int main(){
ios::sync_with_stdio(false);
//freopen("in","r",stdin);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]^=a[i-1];
}
for(int i=0;i<=n;i++){
int x=col(a[i]);
if(f[x]<f[a[i]]){
a[i]=x;
}
if(!f[a[i]]) q.push_back(a[i]);
f[a[i]]++;
}
ll ans=1ll*n*(n+1)/2;
for(int x:q){
ans-=1ll*f[x]*(f[x]-1)/2;
}
cout<<ans;
return 0;
}