题意
小AA找到了一个数列,她想要知道这个数列中所有长度为偶数的区间异或和之和 。
后来她发现这个问题太简单了,于是她加了一个限制,要求区间长度在[L,R]之间,
然后她就不会了。。。
请你告诉她问题的答案。
其中,。
分析
和位运算有关的题统统按位考虑=。=,于是我们枚举二进制的每一位。
问题转化为:有 个数,每个数为
或
,求偶数长度且长度在
且区间和为奇数的区间数量。(真tm绕)
如果区间和为奇数,意味着 。于是我们只关心前缀和的奇偶性。
这样子问题又转化另一个问题:求 中与
不同的数的个数。这个可以用一个前缀和快速求出。
然后由于区间长度为偶数,我们要对奇偶分别开一个数组记录前缀和。。细节还是挺多的。。
最后复杂度是 。
代码如下
#include <bits/stdc++.h>
#define N 100005
const int mod = 1e9 + 7;
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
LL z = 1;
int read(){
int x, f = 1;
char ch;
while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
x = ch - '0';
while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
return x * f;
}
int ksm(int a, int b, int p){
int s = 1;
while(b){
if(b & 1) s = z * s * a % p;
a = z * a * a % p;
b >>= 1;
}
return s;
}
int a[N], s[N], sum[N][2][2];
int main(){
int i, j, n, m, l, r, t = 1, ans = 0, tot, x, y;
n = read(); l = read(); r = read();
for(i = 1; i <= n; i++) a[i] = read();
for(i = 0; i <= 30; i++){
tot = 0;
for(j = 1; j <= n; j++){
if(1 << i & a[j]) s[j] = (s[j - 1] + 1) % 2;
else s[j] = s[j - 1];
}
sum[0][0][0] = 1;
for(j = 1; j <= n; j++){
sum[j][0][0] = sum[j - 1][0][0]; sum[j][0][1] = sum[j - 1][0][1];
sum[j][1][0] = sum[j - 1][1][0]; sum[j][1][1] = sum[j - 1][1][1];
if(j >= l){
x = max(0, j - r); y = j - l;
if(x >= 1) tot = (tot + sum[y][j & 1][1 - s[j]] - sum[x - 1][j & 1][1 - s[j]]) % mod;
else tot = (tot + sum[y][j & 1][1 - s[j]]) % mod;
}
sum[j][j & 1][s[j]]++;
}
ans = (ans + z * t * tot) % mod;
t = t * 2 % mod;
}
printf("%d", (ans + mod) % mod);
return 0;
}

京公网安备 11010502036488号