题意
给数列 (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 imes 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;
}