一.题目链接:
小AA的数列
二.题目大意:
给 n 个数,求区间长度为偶数,且区间长度在 [L, R] 的区间异或和的加和.
三.分析
众所周知,异或题的一种经典解法就是按照分别按照位权计算贡献.
假设当前枚举到二进制位 i,那么当前二进制位 i 对答案的贡献就是 2^i * 异或和第 i 位为 1 的区间个数.
那么问题转化为求解异或和第 i 位为 1 的区间个数.
记 c[i, j] 表示 第偶/奇(i=0/1)个数,前缀异或和为 j 的方案数.
四.代码实现
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int M = (int)1e5; const ll mod = (ll)1e9 + 7; const int inf = 0x3f3f3f3f; const double eps = 1e-8; int a[M + 5]; int main() { // freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); int n, l, r; scanf("%d %d %d", &n, &l, &r); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]), a[i] ^= a[i - 1]; if(l & 1) ++l; if(r & 1) --r; if(l > r) {printf("0\n"); return 0;} ll ans = 0; for(int i = 0; i < 31; ++i) { int c[2][2] = {0}; for(int j = 1; j <= n; ++j) { if(l <= j) ++c[j & 1][(a[j - l]>>i) & 1]; ans = (ans + (1ll<<i) * c[j & 1][((a[j]>>i) & 1) ^ 1]) % mod; if(r <= j) --c[j & 1][(a[j - r]>>i) & 1]; } } printf("%lld\n", ans); return 0; }