1. 程式人生 > >Codeforces 1054D Changing Array

Codeforces 1054D Changing Array

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\n", ans);
    return 0;
}