题目:传送门
题意:求数组元素两两相加后全部异或起来的结果。
思路:暴力求和O(n^2)显然超时,因此可以考虑对所有元素对应的二进制数一位一位算答案。由于是异或,只需要知道某一位“1“”的总个数的奇偶。但是加法涉及进位,不能直接按位计数,那么我们需要把进位考虑在内。高位求和对低位是没有影响的,反之低位求和可能会进位对高位造成影响。因此可以从低位开始枚举,并且把高位给去掉(便于后续二分处理)。那么前 i 位 (从第0位开始) 的数字大小范围 [ 0,2^(i+1)-1 ],而两个数求和后的范围为 [ 0,2^(i+2)-2 ] ,其中满足第 i 位为1的范围为 [ 2^i,2^(i+1)-1 ] U [ 2^(i+1)+2^i ,2^(i+2)-2 ] ; 因此,对去掉高位后的数组排序,求出对于ai来说,与其他元素aj相加后在“有效范围”内的aj总个数 【二分区间端点值-ai 即可】;

1 #include<bits/stdc++.h> 2 #pragma GCC optimize(2) 3 using namespace std; 4 typedef long long LL; 5 typedef pair<int,int> pii; 6 typedef pair<double,double> pdd; 7 const int N=4e5+5; 8 const int inf=0x3f3f3f3f; 9 const int mod=1e9+7; 10 const double eps=1e-9; 11 const long double pi=acos(-1.0L); 12 #define ls (i<<1) 13 #define rs (i<<1|1) 14 #define fi first 15 #define se second 16 #define pb push_back 17 #define mk make_pair 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 LL read() 20 { 21 LL x=0,t=1; 22 char ch; 23 while(!isdigit(ch=getchar())) if(ch=='-') t=-1; 24 while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); } 25 return x*t; 26 } 27 int a[N],t[N]; 28 int main() 29 { 30 int n=read(),ans=0; 31 for(int i=1;i<=n;i++) a[i]=read(); 32 for(int k=1;k<30;k++) 33 { 34 int lim=(1<<k)-1,sum=0; 35 for(int i=1;i<=n;i++) t[i]=a[i]&lim; 36 sort(t+1,t+n+1); 37 for(int i=1;i<=n;i++) 38 { 39 sum+=(upper_bound(t+i+1,t+n+1,lim-t[i])-t)-(lower_bound(t+i+1,t+n+1,(1<<k-1)-t[i])-t); 40 sum+=(upper_bound(t+i+1,t+n+1,(lim<<1))-t)-(lower_bound(t+i+1,t+n+1,(1<<k-1)+(1<<k)-t[i])-t); 41 } 42 if(sum&1) ans+=1<<k-1; 43 } 44 printf("%d ",ans); 45 return 0; 46 }