CodeForces 1323D. Present【位运算】

传送门

题意

给数列 \(a_1,a_2,...,a_n\),求 \((a_1+a_2)\oplus(a_1+a_3)\oplus...\oplus(a_1+a_n)\oplus(a_2+a_3)\oplus...\oplus(a_2+a_n)\oplus...\oplus(a_{n-1}+a_n)\)
\(\oplus\)”为异或运算。

题解

思路非常巧妙的位运算思维题,div2 场里整场比赛就 100 左右个人做出来,难度对于不是非常熟悉位运算的人来说是比较大的。
可以考虑答案的每一位是 0 还是 1。考虑第 \(w\) 位,如果有奇数对 \(a_i+a_j\) 的第 \(w\) 位为 \(1\),那么答案的 \(w\) 位就是 \(1\)
\(a_i\) 的每个数小于等于 \(w\) 位拿出来形成 \(b_i\),即构造数列 \(b\),使 \(b_i=a_i\&(2^{w+1}-1)\)\(a_i\) 中大于 \(w\) 的位置对于 \(w\) 位是没有影响的嘛。可以发现现在 \(b_i\) 最小为 \(1\),最大为 \(2^{w+1}-1\),所以 \(b_i+b_j\) 取值在区间 \([2,2^{w+2}-2]\) 内,而此时要使 \(w\) 位为 \(1\),那么 \(b_i+b_j\) 就应该在 \([2^w,2^{w+1}-1]\cup[2^{w+1}+2^w,2^{w+2}-2]\) 里,那如果确定了 \(b_i\),满足 \(b_i+b_j\)\(w\) 位为 \(1\)\(b_j\) 就在区间 \([2^w-b_i,2^{w+1}-1-b_i]\cup[2^{w+1}+2^w-b_i,2^{w+2}-2-b_i]\) 里,那么 \(b_j\) 的个数就是满足要求的 \(b_i+b_j\) 的对数了。那么要求这个也比较简单了,只需要将 \(b\) 排序,枚举 \(b_i\),在 \(b_1,b_2,...,b_{i-1}\) 中找满足要求的 \(b_j\) 的个数就可以了,因为 \(b\) 有序,所以直接用 lower_bound 和 upper_bound 可以轻松求解区间中包含的数的数量。最后如果总的 \(b_j\) 个数为奇数,那么答案 \(w\) 位就是 \(1\)
复杂度 \(O(NlogNlogC)\),大概算一下,最坏已经到达 \(2\times 10^8\) 级别了,但是CF评测机不愧是全球最快,1s多就可以跑过

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=4e5+10;
const int M=1e7+10;
int n,a[N],b[N],ans;

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int w=0;w<=24;w++){
        for(int i=1;i<=n;i++) b[i]=a[i]&(1<<w+1)-1;
        sort(b+1,b+n+1);
        LL temp=0;
        for(int i=1;i<=n;i++){
            int posl=lower_bound(b+1,b+i,(1<<w)-b[i])-b;
            int posr=upper_bound(b+1,b+i,(1<<w+1)-1-b[i])-b;
            temp+=posr-posl;
            posl=lower_bound(b+1,b+i,(1<<w+1)+(1<<w)-b[i])-b;
            posr=upper_bound(b+1,b+i,(1<<w+2)-2-b[i])-b;
            temp+=posr-posl;
        }
        if(temp%2==1) ans+=(1<<w);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12443264.html
今日推荐