原题链接
想到了按位计算,然后就没有然后了(.)
思路:
以样例2为例,ans = 2是因为(i,j)和在第二位上为1的序对有奇数个,那么怎么计算奇数个呢?(本蒟蒻卡这了).能够影响第i位的和是否为1的只有1~i位的数字,我们对每个a[i]%2i = b[i],对于每个b[i],我们需要找到与它的和第i位为1的个数.
注意这里不能简单的考虑为b[i]在第k位为0,找第k位为1的个数,因为存在进位.所以只能考虑和,每个b[i]的取值范围在[0,2k-1],那么b[i]+b[j]的取值范围是[0,2k+1-2].第k位为1的b[i]+b[j]的取值范围是[2k-1,2k-1],[2k+2k-1,2k+1-2],确定了b[i]后,b[j]的范围就求出来了,然后二分找即可.
一开始没想出来怎么去重,结果发现限定二分范围就行了.
Code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 400010,M =40;
int n,a[N],b[N];
LL logs[M];
int get(int s,int n)
{
int l = 0,r = n;
while(l<r)
{
int mid = l+r+1>>1;
if(b[mid]<=s) l = mid;
else r = mid-1;
}
return r;
}
int main()
{
scanf("%d",&n);
int ans = 0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
b[0] = -1e9;
for(int i=0;i<M;i++) logs[i] = 1ll<<i;
for(int i=0;i<32;i++)
{
int k = i+1,cnt=0;
for(int j=1;j<=n;j++) b[j] = a[j]%logs[k];
sort(b+1,b+n+1);
for(int j=1;j<=n;j++)
{
int c = logs[k-1]-b[j]-1,d=logs[k]-1-b[j];
int l = get(c,j-1);
int r=get(d,j-1);
if(l>r) continue;
cnt+=r-l;
c = logs[k]+logs[k-1]-b[j]-1,d=logs[k+1]-2-b[j];
l = get(c,j-1),r = get(d,j-1);
if(l>r) continue;
cnt+=r-l;
}
if(cnt&1) ans|=(1<<i);
}
printf("%d\n",ans);
return 0;
}