异或和之和
拆位+贡献法
思路:刚开始考虑遍历L和R,同时可以用一个二维数组存储算过的值,但是时间复杂度还是O(n^2),所以这种还是要拆位和利用贡献法
可以对于每个位,一定区间内,如果有奇数个1则异或值为1,有偶数个1则异或值为0,且某个位对这个区间内的贡献为2^i
于是我们可以遍历每个位,本题最多就20个位,同时利用前缀和记录到该数时几个位是1,如果是奇数,那这个数到前面所有数这个区间和这个数减去前缀和为偶数的区间都有贡献,偶数也是,如图
这里res,b,n0,n1都要开longlong!!不然过不了40%
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
int main()
{
int n;
cin>>n;
vector<ll> v(n);
for(int i=0;i<n;i++) cin>>v[i];
ll res=0;
for(int i=20;i>=0;i--)
{
//b表示1的个数前缀和,n0表示前面前缀和为偶数的个数,n1表示前面前缀和为奇数的个数
//n0初始化为1因为当某一位前缀和为奇数时,这个数及前面所有数这个区间也贡献了
ll b=0,n0=1,n1=0;
for(int j=0;j<n;j++)
{
//该位是否为1
int bit=(v[j]>>i)&1;
b+=bit;
//有奇数个1
if(b%2)
{
res+=(1<<i)*n0;
n1++;
}
//有偶数个1
else
{
res+=(1<<i)*n1;
n0++;
}
}
}
cout<<res<<endl;
return 0;
}