bzoj4017 小Q的无敌异或 数学

博客探讨了如何处理与异或相关的数学问题,通过分析第k位对异或求和的影响,提出O(Nlog A)和O(NlogNlog sum|A|)的解决方案,涉及离散化和树状数组技术。
摘要由CSDN通过智能技术生成

        一般和异或相关的求和都是一位一位来的。这题也一样。

       首先看第一问。令sum[i]=a[1]^a[2]^...^a[i],那么xor(l,r)=sum[l-1]^sum[r],考虑每一位对答案带来的影响。假设现在考虑二进制第k位(从低到高)对答案的影响。

       对于sum[x],它的第k位对答案的影响为2^k*t,其中t为1..x-1中sum[]值二进制第k位与sum[x]不同的数的个数。那么在k确定的情况下O(N)扫一遍即可。时间复杂度O(Nmax{log A})。

       然后看第二问,继续考虑第k位对答案的影响。令sum[i]=sum[i-1]+a[i],则sum(l,r)=sum[r]-sum[l-1],那么第k位对答案有影响当且仅当存在奇数对(x,y),满足x<=y且sum[x-1]和sum[y]的第k为不同。考虑在mod (2^(k+1))的意义下,任意;两个sum[l]和sum[r],它们的第k为不同,当且仅当sum[r]-sum[l]>=2^k,或者sum[r]+2^k+1-sum[l]>=2^k。因此只需要考虑有多少对(x,y),x<=y,满足sum[y]-sum[x-1]>=2^k 或者sum[y]<sum[x-1] 且 sum[x-1]-sum[y]<=2^k即可,用树状数组维护即可。时间复杂度O(NlogNlog sum|A|)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 100005
#define mod 998244353
using namespace std;

int n,cnt,a[N],c[N]; ll m,sum[N],num[N],hash[N],p[N];
void ins(int x,int t){
	for (; x<=cnt; x+=x&-x) c[x]^=t;
}
int getxor(int x){
	int t=0; for (; x; x-=x&-x) t^=c[x];
	return t;
}
int find(ll x){
	if (x<0) return 0; int l=1,r=cnt+1;
	while (l+1<r){
		int mid=(l+r)>>1;
		if (hash[mid]<=x) l=mid; else r=mid;
	}
	return l;
}
int main(){
	scanf("%d",&n); int i; ll k,ans=0;
	for (i=1; i<=n; i++){
		scanf("%d",&a[i]); sum[i]=sum[i-1]^a[i];
		m=max(m,sum[i]);
	}
	for (k=1; k<=m; k<<=1){
		c[0]=1; c[1]=0;
		for (i=1; i<=n; i++){
			int tmp=(sum[i]&k)?1:0;
			ans=(ans+k*c[tmp^1]%mod)%mod; c[tmp]++;
		}
	}
	printf("%lld ",ans); ans=0;
	for (i=1; i<=n; i++) sum[i]=sum[i-1]+a[i];
	for (k=1; k<=sum[n]; k<<=1){
		for (i=0; i<=n; i++) num[i]=p[i]=sum[i]&((k<<1)-1);
		sort(num,num+n+1); hash[cnt=1]=num[0];
		memset(c,0,sizeof(c));
		for (i=1; i<=n; i++)
			if (num[i]!=num[i-1]) hash[++cnt]=num[i];
		int tmp=0;
		for (i=0; i<=n; i++){
			tmp^=getxor(find(p[i]-k))^getxor(find(p[i]))^getxor(find(p[i]+k));
			ins(find(p[i]),1);	
		}
		if (tmp) ans|=k;
	}
	printf("%lld\n",ans);
	return 0;
}


by lych

2016.2.27

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值