题目大意:给你一个大小是n的序列,求两两之间相加进行异或之后的答案。
这个题目我并没有想到怎么写,有点偷懒于是就去看了题解。。
题解很套路。。。
题解:
因为这个是用到了异或,所以不可避免的肯定要用到二进制。
所以考虑进行拆位,当我要考虑第 (i) 位,那么比这一位高的都不会产生影响,所以对所有的数取模处理一下,然后再枚举每一个数满足条件的一个区间,这个可以二分来解决。
因为每一个数的区间是 (0=<a_i<=2^{i+1}-1),所以之和的区间是 (0<=a_i<=2^{i+2}-2)
条件:
- 两个数之和在 ([2^i,2^{i+1}-1])
- 两个数之和在 ([2^{i+1}+2^i,2^{i+2}-2])
//我还以为会wa,比较复杂度我大致算了一下可能会超时一点点。。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=4e5+7;
typedef long long ll;
int a[maxn],bit[maxn],n;
int Ans[maxn];
int judgemin(int sum,int x,int y){
// printf("min sum=%d x=%d
",sum,x);
int l=1,r=y,ans=inf;
while(l<=r){
int mid=(l+r)>>1;
// printf("mid=%d bit=%d
",mid,bit[mid]);
int all=bit[mid]+x;
if(all>=sum) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int judgemax(int sum,int x,int y){
// printf("max sum=%d x=%d
",sum,x);
int l=1,r=y,ans=0;
while(l<=r){
int mid=(l+r)>>1;
// printf("bit[%d]=%d
",mid,bit[mid]);
int all=bit[mid]+x;
if(all<=sum) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<=25;i++){
int mod=1<<(i+1),ans=0;
// printf("mod=%d
",mod);
for(int j=1;j<=n;j++) bit[j]=a[j]%mod;
sort(bit+1,bit+1+n);
for(int j=1;j<=n;j++){
int x=bit[j];
// printf("j=%d bit[%d]=%d
",j,j,bit[j]);
int lc=judgemin(1<<i,x,j-1),rc=judgemax(mod-1,x,j-1);
// printf("fi lc=%d rc=%d
",lc,rc);
ans+=max(0,rc-lc+1);
lc=judgemin((1<<(i+1))+(1<<i),x,j-1),rc=judgemax((1<<(i+2))-2,x,j-1);
// printf("se lc=%d rc=%d
",lc,rc);
ans+=max(0,rc-lc+1);
}
Ans[i]=(ans&1);
// printf("Ans[%d]=%d
",i,Ans[i]);
}
int ans=0;
for(int i=25;i>=0;i--){
ans=ans*2+Ans[i];
}
printf("%d
",ans);
return 0;
}