异或和之和

数论典题,拆成二进制位进行分析,首先用计算异或前缀和,便于区间操作,对于区间[L,R],其区间异或值为 $Xor[L-1]⊕Xor[R]$,统计区间的在第 $i$ 位为$1$的个数,那么根据乘法原理,有$cnt$个$1$和剩余的$0$组合,然后这个是算出了有多少种方案让当前这一位有贡献,要算出答案需要对cnt[i] (n - cnt[i])乘以1 << k - 1(k表示枚举的是二进制下的第几位)

以下介绍两种做法:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=2e6+10;
int n,s[N],res;
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        s[i]=s[i-1]^x;
    }
    for(int i=0;i<=30;i++){
        int cnt=0;
        for(int j=1;j<=n;j++)
            if((1<<i)&s[j]) cnt++;
        res+=(1<<i)*(n-cnt+1)*cnt;
    }
    cout<<res;
}
#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=2e6+10;
int n,s[N],cnt1[N],cnt2[N],res;
signed main(){
    cin>>n;
    for(int i=0;i<=30;i++) cnt2[i]=1;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        s[i]=s[i-1]^x;
        for(int j=30;j>=0;j--){
            if((1<<j)&s[i]) res+=(1<<j)*cnt2[j],cnt1[j]++;
            else res+=(1<<j)*cnt1[j],cnt2[j]++;
        }
    }
    cout<<res;
}

 

posted @ 2024-02-02 17:29  o-Sakurajimamai-o  阅读(97)  评论(0)    收藏  举报
-- --