感受
思路很常规,二进制拆位算贡献,但是苦逼的我debug一下午,代码实现能力有待提高


思路


常规做法,枚举区间左端点L,如何找右端点呢?
异或题,肯定要想到二进制拆位,于是,问题就简单转化为对于某一二进制位,算出这个位对答案的贡献。

贡献 = ((ll)1<<i) * (区间种数) 

于是,考虑怎么算区间种数?
区间有什么特性吗?显然,把区间里的每个数拆成二进制,统计第i位的值,作一个求和,如果为奇数,那么对答案有贡献,否则无贡献。
于是,我们言归正传,看看此题


首先题目有两个限制条件:
(1)区间长度为偶数
(2)区间长度属于[l, r]
其实,限制(2)很好转化,我们枚举左端点L,那么右端点取值为[L + l - 1, min(L + r - 1, n)](如果区间不合法,就肯定无贡献,比如区间[5, 2])
如何满足条件(1)呢?
其实也很简单,右端点的取值奇偶性与L的奇偶性相反即可,自己画画就知道了。

那我们考虑最后一个问题,如何统计枚举左端点为L的答案呢?
设右端点取值为[R1, R2],会成为的R有以下特性
(1)R的奇偶性与L的奇偶性不同
(2)L到R中,对应二进制位为1的个数为奇数
显然暴力check会T
所以,我们需要做几个前缀和

sum[pos][i] 前pos个数中,二进制第i位为1的个数之和
num[0/1][pos][i][0/1];///前pos个数中, 考虑[偶/奇]下标 sum[1-pos][i]为[偶数/奇数]的个数
区间个数 = num[(L - 1) % 2][R2][i][!(sum[L - 1][i] % 2)] - num[(L - 1) % 2][R1 - 1][i][!(sum[L - 1][i] % 2)];

AC代码

#include <bits/stdc++.h>
#define ls o << 1
#define rs o << 1 | 1
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const ll mod = 1e9 + 7;
int num[2][maxn][35][2];///前pos个数中, 考虑[偶/奇]下标 sum[pos][i]为[偶数/奇数]的个数
int sum[maxn][35];///0 - 32  sum[pos][i]前pos个数中,第i位为1的个数的奇偶性
int n, l, r;

void solve(int x, int pos){
    int i = 0;
    while(x){
        if(x % 2){
            sum[pos][i] = 1;
        }
        else{
            sum[pos][i] = 0;
        }
        x /= 2; i++;
    }
}
void solve1(){
    for(int pos = 1; pos <= n; pos++){
        for(int i = 0; i < 35; i++){
            sum[pos][i] += sum[pos - 1][i];
            if(sum[pos][i] % 2){
                num[pos % 2][pos][i][1] = 1;
                num[pos % 2][pos][i][0] = 0;
            }
            else{
                num[pos % 2][pos][i][0] = 1;
                num[pos % 2][pos][i][1] = 0;
            }
        }
    }
    for(int k = 0; k <= 1; k++){
        for(int pos = 1; pos <= n; pos++){
            for(int i = 0; i < 35; i++){
                for(int j = 0; j <= 1; j++){
                    num[k][pos][i][j] += num[k][pos - 1][i][j];
                }
            }
        }
    }

}
int main(){
    int tmp;
    scanf("%d%d%d", &n, &l, &r);
    for(int i = 1; i <= n; i++){
        scanf("%d", &tmp);
        solve(tmp, i);
    }
    solve1();
    int L, R1, R2;
    ll ans = 0;
    for(L = 1; L <= n; L++){
        R1 = l + L - 1; R2 = min(r + L - 1, n); if(R1 > R2) continue;
        for(int i = 0; i < 35; i++){
            int get;
            get = num[(L - 1) % 2][R2][i][!(sum[L - 1][i] % 2)] - num[(L - 1) % 2][R1 - 1][i][!(sum[L - 1][i] % 2)];
            ans = ans + ((ll)1 << i) % mod * get % mod;
            ans %= mod;
        }
    }
    printf("%lld\n", ans);
    return 0;
}
/*
2 1 2
4 4

*/