异或和之和(组合数学)
思路:考虑每位对答案的贡献,因为最大为 ,所以最大一共64位。
储存每一个1的个数,贡献产生只能出现两种情况
一个1,两个0.
三个1。
然后用组合数和加法原理对贡献求和即可。
即第 位的贡献
计算组合数除法时需要用到逆元。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,mod=1e9+7;
int a[100];
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
ll inv(ll x){
return ksm(x,mod-2);
}
ll f(ll x,ll y){
if(x<y) return 0;
ll ans=1;
for(int i=0;i<y;i++)
ans=ans*(x-i)%mod,ans=ans*inv(i+1)%mod;
return ans;
}
int main(){
int n ;
scanf("%d",&n);
for(int i=1;i<=n;i++){
ll x,j=0;
scanf("%lld",&x);
while(x){
if(x&1) a[j]++;
x>>=1,j++;
}}
ll ans=0;
for(int i=0;i<64;i++){
ans+=(1LL<<i)%mod*(f(a[i],3)+f(n-a[i],2)*a[i]%mod)%mod;
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}