1323D

题目:传送门 

题意:求数组元素两两相加后全部异或起来的结果。

思路:暴力求和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 }
AC代码
原文地址:https://www.cnblogs.com/DeepJay/p/12554996.html