Description
小AA找到了一个数列,她想要知道这个数列中所有长度为偶数的区间异或和之和 。
后来她发现这个问题太简单了,于是她加了一个限制,要求区间长度在[L,R]之间,
然后她就不会了。。。
请你告诉她问题的答案。
Solution
异或问题优先考虑二进制位,对于这个问题,我们需要考虑偶数长度的区间,那么先对 做处理,因为如果 , 是奇数其实加一/减一没有区别。然后处理一下前缀异或和, 因为我们有性质 。最后我们要找到哪些是有贡献的,我们考虑枚举右端点,如果当前点的异或是 1,那么需要在前面找异或为 0 的点才有贡献,反之如果当前点的异或是 0,那么要在前面找异或为 1 的点才有贡献,此外,奇数下标要找奇数下标,偶数下标要找偶数下标,才能构成偶数长度区间。
所以我们可以用 dp[i][j] 维护前面符合条件的状态数,第一维表示当前位为 0/1, 第二维表示当前下标为 奇/偶的状态数,直接计算贡献即可。
Code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 5; const int mod = 1e9 + 7; int a[N]; 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]; } if(l & 1) l++; // 保证偶数长度 if(r & 1) r--; if(l > r) { cout << 0 << "\n"; return 0; } ll ans = 0; for(int i = 0; i < 32; i++) { ll p = (1LL << i); ll dp[2][2] = {0}; ll num = 0; for(int j = l; j <= n; j++) { dp[(a[j - l] >> i) & 1][(j - l) & 1]++; num += dp[((a[j] >> i) & 1) ^ 1][j & 1]; num %= mod; if(j >= r) { dp[(a[j - r] >> i) & 1][(j - r) & 1]--; } } ans += num * p % mod; ans %= mod; } cout << ans << "\n"; return 0; }