题目链接
题意:
给定一个数列,找出这个数列中长度为偶数的连续子列的异或和
并且要求长度为偶数的同时满足在L到R之间
最后结果mod 1e9+7
题解:
n,L,R<=1e5,所以不能考虑n2暴力了
之前比较经典的就有选任意两位数异或的总和
那个题可以考虑枚举二进制位,然后看每一位的贡献有多少
其实就是每一位有多少种异或后成1的方法
算出来之后乘这一二进制位的权重即可
这道题肯定也是类似,需要对每一二进制位进行分开考虑
然后一步一步分析差别
首先,这道题需要考虑的是一个连续子列
连续子列我们可以维护一个前缀和
如果sum[r] xor sum[l−1]==1说明l−r的贡献为1
如果xor为0,说明这之间的异或也为0,没有贡献
那么枚举每个前缀的二进制位
看在某一个二进制位上这个前缀的前面有多少个与他相反的前缀
然后每一二进制位综合起来乘上权值就可以算出来最后的结果
然后,考虑一下偶数的限制
其实很简单,两个奇数或者两个偶数相减才是偶数
比如前缀下标l是1,r是5,相减是4个,中间有数2,3,4,5
l是2,r是4,相减2个,中间数是3,4
所以对把刚才那个维护个数的数组再加一维,这一维存奇偶数位置
这样就把偶数的限制解决了
最后解决一下L,R的限制
这样其实数组不用改变
你只要保证,数组中的个数所对应的位置和当前这个位置是在L到R即可
那么,其实就是对于每个位置,如果他到和当前位置如果距离刚好是L
就把这个位置作为贡献加入,直到往后枚举如果他和枚举的位置距离成R的时候
再把他减去,就保证了这个位置和后面的位置形成的区间长度都在L到R之间
这样一步一步解决完了
只要写出来代码就行了
还有一个比较直接的问题,题目没有限定L,R一定为偶数
如果区间里只有奇数,即L==R并且为奇数那么结果肯定是0
还有如果L,R为奇数的时候,但不可能出现奇数,所以往中间减少一下
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll c[2][2],a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,l,r;
cin>>n>>l>>r;
if(l==r&&l&1){cout<<0;return 0;}
if(l&1)l++;if(r&1)r--;
for(int i=1;i<=n;i++)cin>>a[i],a[i]^=a[i-1];
ll ans=0;
for(int i=0;i<=31;i++){
memset(c,0,sizeof c);
for(int j=1;j<=n;j++){
if(j>=l)c[j&1][(a[j-l]>>i)&1]++;
ans=(ans+c[j&1][(a[j]>>i)&1^1]*(1ll<<i)%mod)%mod;
if(j>=r)c[j&1][(a[j-r]>>i)&1]--;
}
}
cout<<ans;
return 0;
}