按位计算贡献

要求区间[l,r]的异或和,只需要知道[1,r]和[1,l-1]的异或和即可。
所以我们先对序列进行前缀异或和处理一下。这样可以O(1)计算任意一个子区间的异或和。
先不考虑要求偶数长度的限制,只考虑区间长度的限制。
我们知道 对于每一位而言,前缀异或和,该位要么是0要么是1,而要想对区间[l,r]对答案有贡献,则需要区间[1,r]和[1,l-1]的前缀异或和在该二进制位上的值相反。
那么这个很简单,我们只需要开一个cnt[0/1]数组统计每一二进制位上异或前缀和位0/1的个数。
那么要求长度是偶数呢?
容易知道奇+偶=奇、偶+偶=偶 所以cnt可以在多开一维 cnt[0/1][0/1]表示前缀异或和中 奇数/偶数位置的前缀和位0/1
那么枚举右端点j,以当前点为右端点的贡献就是,看有前缀中有多少个与到该二进制位的异或值相反(保证有贡献),并且在数列中的下标奇偶性相同(保证长度是偶数),在乘上1<<x即可(x为二进制的第x位)
如果当前枚举的右端点j大于r,那么就需要把最前面那个统计的cnt删除即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll cnt[2][2],a[1<<17];
int main()
{
    int n,l,r;
    cin>>n>>l>>r;
    for(int i=1;i<=n;i++) cin>>a[i],a[i]^=a[i-1];///前缀异或和
    ll ans=0;
    for(int i=0;i<32;i++){
        memset(cnt,0,sizeof cnt); //cnt第一维表示位置的奇偶性,第二维表示前缀异或和的值
        for(int j=l;j<=n;j++){
            cnt[(j-l)&1][(a[j-l]>>i)&1]++;///加入左端点  
            if(j>r)cnt[(j-r-1)&1][(a[j-r-1]>>i)&1]--;//删除在cnt中,最左边的那个点的贡献
            ans=(ans+cnt[j&1][((a[j]>>i)&1)^1]*(1ll<<i)%mod)%mod;///计算贡献
        }
    }
    cout<<ans;
    return 0;
}