CF1322B - Present 思维

CF1322B - Present

题意

N N 个数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n ,现在求 ( a 1 + a 2 ) ( a 1 + a 3 ) ( a n 1 + a n ) (a_1+a_2)⊕(a_1+a_3)⊕···⊕(a_{n-1}+a_n) N 400000 N\leq400000

题解

直接算是不行的
这里考虑计算二进制下 a n s ans 的每一位
对于 a n s ans 的第 k k 位答案,我们只需要考虑数 a i a_i [ 0 , k ] [0,k] 位,因为超过 k k 位对第 k k 位没有影响
所以我们记 b i = a i % 2 k + 1 b_i=a_i\%2^{k+1} ,这样就保留了 [ 0 , k ] [0,k] 位的影响
然后我们要第 k k 位结果是 1 1 b i + b j b_i+b_j
而第 k k 位为1的数的范围为 [ 2 k , 2 k + 1 1 ] [2^k,2^{k+1}-1] [ 2 k + 1 + 2 k , 2 k + 2 2 ] [2^{k+1}+2^k, 2^{k+2}-2]
后面 2 k + 2 2 2^{k+2}-2 这么来的: b [ i ] [ 0 , 2 k + 1 1 ] b[i]∈[0,2^{k+1}-1] ,这里两个数,所以就是 2 k + 2 2 2^{k+2}-2
可以通过枚举 b i b_i 求得对应的 b j b_j 数量即可

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 4e5 + 10;

int N;
int a[MAX], b[MAX];

int pos(int x) { return lower_bound(b + 1, b + 1 + N, x) - b; }

int main() {
    scanf("%d", &N);
    for (int i = 1; i <= N; i++) scanf("%d", &a[i]);
    int ans = 0;
    for (int bit = 0; bit <= 25; bit++) {
        int num = 1 << bit;
        for (int i = 1; i <= N; i++) b[i] = (a[i] & (2 * num - 1));//和a[i] % (2 * num - 1)一样的
        sort(b + 1, b + 1 + N);//排序
        int cnt = 0;
        for (int i = 1; i <= N; i++) {
            cnt += pos(4 * num - b[i] - 1) - pos(3 * num - b[i]);//[3 * num, 4 * num - 2]间的数
            cnt += pos(2 * num - b[i]) - pos(num - b[i]);//[num, 2 * num - 1]间的数
            if ((2 * b[i]) & num) cnt--;//如果b[i]+b[i]的第k位是1, 就减去这种
        }
        if ((cnt / 2) & 1) ans ^= 1 << bit;//这里cnt/2是因为我们会算b[i]+b[j]和b[j]+b[i]两种
    }
    printf("%d\n", ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44282912/article/details/104869636