1. 程式人生 > >Mail.Ru Cup 2018 Round 1 D

Mail.Ru Cup 2018 Round 1 D

題意:

給定n個數的序列,每個數的二進位制數看作是k位的,你可以改變任意一個數,使得區間異或和不為零的個數最多,

改變的規則可以是把每個數跟  2^k - 1 進行異或

思路:

首先我們需要知道區間異或和可以有區間字首異或和得到,,即 a_i-j = sum_j ^ sum_(i-1);

還要知道這樣的一段區間,不論改變那個數,改變幾個,區間的異或和只有兩種可能; // 剛剛知道

這樣的話,我們就要使得字首異或和中相同的數的總的數量最少,

其實是個貪心,對於當前的數a_i 我們是否選擇改變,有兩種影響,就是他們字首和的值對後面的影響,我們要使得總數儘量小的話,那就讓前面出現的個數儘量少;

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;


const int maxn = 1e5 + 7;

ll n, k;
map<ll, ll> mp;

int main() {
    scanf("%lld%lld", &n, &k);
    ll ans = n * (n + 1) / 2LL;
    ll pre = 0, max_ = (1<<k)-1;
    mp[0] = 1;
    for(int i = 1; i <= n; ++i) {
        ll x; scanf("%lld", &x);
        ll t1 = pre ^ x;
        ll t2 = t1 ^ max_;
        if(!mp.count(t1)) mp[t1] = 0;
        if(!mp.count(t2)) mp[t2] = 0;
        if(mp[t1] <= mp[t2]) {
            ans -= mp[t1];
            mp[t1]++;
            pre = t1;
        }
        else {
            ans -= mp[t2];
            mp[t2]++;
            pre = t2;
        }
    }
    printf("%lld\n", ans);
    return 0;
}