Present CodeForces - 1322B

原题链接
想到了按位计算,然后就没有然后了(.)
思路:
  以样例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;
}
posted @ 2021-06-09 02:35  acmloser  阅读(18)  评论(0编辑  收藏  举报