Codeforces 1054D Changing Array
做法:给定一个序列,每个数可以把在2进制k位下取反,也可以不变,在改变后,这个序列异或和不为0的区间的个数。考虑如何求出尽可能少的异或为0的序列,对序列求前缀之后,就相当与问这个前缀的序列中,有多少对的值相同,注意还有开始的0。那么对于所有数取值为min(a,~a),现在我们需要最小化,更新后同一种数中出现的相同的数对的个数,即(C(a,2) + C(w-a,2)),w是这种数的个数,a是取反的数的个数,当(a = frac{w}{2})时,答案最小,对于每一种都计算即可。
#include <bits/stdc++.h>
typedef long long ll;
const int N = 2e5 + 7;
using namespace std;
int n, k, lim, a[N];
map<int,int> M;
ll C(ll x) { return x*(x-1LL)>>1LL; }
int main() {
scanf("%d%d",&n,&k);
lim = (1ll<<k) - 1ll;
for(int i = 1; i <= n; ++i) scanf("%d",&a[i]);
for(int i = 2; i <= n; ++i) a[i] ^= a[i-1];
for(int i = 0; i <= n; ++i) a[i] = min(a[i], lim-a[i]), ++M[a[i]];
ll ans = C(n+1);
for(map<int,int>::iterator it = M.begin(); it != M.end(); ++it) {
int w = (*it).second;
ans -= C( w>>1 ) + C( w - (w>>1) );
}
printf("%lld
", ans);
return 0;
}