Codeforces 1323 D. Present(二进制+二分)

在这里插入图片描述

题意:

给一个长度为 n n 的序列 a a
要求计算 ( a 1 + a 2 ) ( a 1 + a 3 ) ( a 1 + a n ) ( a 2 + a 3 ) ( a 2 + a n ) ( a n 1 + a n ) (a_1+a_2)⊕(a_1+a_3)⊕…⊕(a_1+a_n)⊕(a_2+a_3)⊕…⊕(a_2+a_n)…⊕(a_{n−1}+a_n)

我们分析答案的每一位,如果答案的第 i i 位是 1 1 ,这意味着有奇数个 ( j , k ) (j,k) 满足 a j + a k aj+ak 的第 i i 位是 1 1

首先我们要砍掉高于 i i 位的信息(这对答案不产生影响),即让 b j = a j b_j=a_j%(1<<(i+1)) ,于是第 i i 位是 1 1 b j + b k b_j+b_k 的值只能在区间 [ 2 i , 2 i + 1 1 ] [ 2 i + 1 + 2 k , 2 i + 2 1 ] [2^i,2^{i+1}-1]∪[2^{i+1}+2^k,2^{i+2}−1]
这时如果固定 j j 的值, b k b_k 的值的区间就是 [ 2 i b j , 2 i + 1 1 b j ] [ 2 i + 1 + 2 k b j , 2 i + 2 1 b j ] [2^i−b_j,2^{i+1}−1−b_j]∪[2^{i+1}+2^k−b_j,2^{i+2}−1−b_j] ,因此能在排序后用二分快速计算满足 b j + b k b_j+b_k 的第 i i 位是 1 1 k k 的个数。

AC代码:

int n, m, k;
int res, cnt, ans;
const int N = 4e5 + 10;
int a[N];
int b[N];
int main()
{
    sd(n);
    rep(i, 1, n)
        sd(a[i]);
    ans = 0;
    rep(i, 0, 26)
    { //a[i]一定小于1<<26
        int mod = 1 << (i + 1);
        rep(j, 1, n)
            b[j] = a[j] % mod;
        int s = 0;
        sort(b + 1, b + n + 1); 
        rep(j, 1, n)
        {
            int l, r;
            l = lower_bound(b + 1, b + n + 1, (1 << i) - b[j]) - b;
            r = lower_bound(b + 1, b + n + 1, (1 << (i + 1)) - b[j]) - b - 1;
            s += (r - l + 1); //统计2^i到2^(i+1)-1区间内的解
            l = lower_bound(b + 1, b + n + 1, (1 << i) + (1 << (i + 1)) - b[j]) - b;
            r = lower_bound(b + 1, b + n + 1, (1 << (i + 2)) - b[j]) - b - 1;
            s += (r - l + 1); //统计2^(i+1)+2^i到2^(i+2)-1区间内的解
            if ((b[j] + b[j]) & (1 << i))
                s--; //自己和自己相加的不算
        }
        if ((s / 2) & 1)
            ans += 1 << i; //小于j和大于j的都记录了所以个数要除以2
    }
    pd(ans);
    return 0;
}
发布了709 篇原创文章 · 获赞 424 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/qq_43627087/article/details/104729808
今日推荐