[CL-22] 异或和之和

CL-22

二进制拆分。

对于枚举到的每一个二进制位 \(i\),注意到其对答案的贡献只有 \(0\)\(2^{i}\) 两种情况

考虑什么时候贡献是 \(2^i\),可以发现,当选入奇数个该位为 \(1\) 的数之后,对答案的贡献是 \(2^{i}\)

因此变成求选出奇数个为 \(1\) 的数的方案数

设该位为 \(1\) 的数有 \(a\) 个,为 \(0\) 的数有 \(b\) 个,答案为 \(2^{b}\times\sum\limits^{a}_{i\in\{1,3,5,7\cdots\}}C^{i}_{a}\)

这样就可以做了,但是还有一个进一步的结论

\[\sum\limits^{a}_{i\in\{1,3,5,7\cdots\}}C^{i}_{a}=2^{a-1} \]

不会证明,但是它是对的

复杂度 \(n\log(2^{31})\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1e9+7;
int power(int a,int t){
	int base=a,ans=1;
	while(t){
		if(t&1){
			ans=ans*base%p;
		}
		base=base*base%p;
		t>>=1;
	}
	return ans;
}
int n;
int a[1000001];
int cnt0[33],cnt1[33];
signed main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>a[i];
		for(int j=1;j<=32;++j){
			if(a[i]&1){
				cnt1[j]++;
			}
			else{
				cnt0[j]++;
			}
			a[i]>>=1;
		}
	}
	int ans=0;
	for(int i=1;i<=32;++i){
		if(!cnt1[i]) continue;		
		ans+=power(2,cnt1[i]-1)*power(2,cnt0[i])%p*power(2,i-1)%p;
		ans%=p;
	}
	cout<<ans<<endl;
}
posted @ 2024-09-27 21:37  HaneDaniko  阅读(69)  评论(15编辑  收藏  举报