序列子区间异或和。
我们记录每个区间对每一位的贡献值;
如果我们对区间长度没有限制我们只需要我们前边的几个区间对第i位的贡献值。
xor[i]^xor[j] == 1
xor[i] == xor[j]^1
最后就是权值乘价值。
对于区间长度无任何要求
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100005
const ll Mod = 1e9+7;
ll a[N];
ll n;
ll Num[2];///代表第n位贡献 0 还是 1
ll Solve()
{
ll res = 0;
for(ll j=0; j<31; j++)
{
ll num = 0;
memset(Num,0,sizeof(Num));
Num[0]=1;///长度为 0 的区间可以存在且贡献值为0 的加一
for(ll i=1; i<=n; i++)
{
Num[(a[i]>>j)&1]++;///更新的是我们要的区间值
num = (num + (Num[!(a[i]>>j&1)]))%Mod;
}
res = (res + num*((1LL<<j)%Mod))%Mod;
}
return res;
}
int main()
{
while(~scanf("%lld",&n))
{
memset(a,0,sizeof(a));
for(ll i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
}
for(ll i=1;i<=n;i++)
a[i]=a[i-1]^a[i];
printf("%lld\n",(Solve()+Mod)%Mod);
}
}
例题:
小AA 的数列
题目描述
小AA找到了一个数列,她想要知道这个数列中所有长度为偶数的区间异或和之和 。
后来她发现这个问题太简单了,于是她加了一个限制,要求区间长度在[L,R]之间,
然后她就不会了。。。
请你告诉她问题的答案。
后来她发现这个问题太简单了,于是她加了一个限制,要求区间长度在[L,R]之间,
然后她就不会了。。。
请你告诉她问题的答案。
输入描述:
第一行三个数 n, L, R(n<=105,1<=L<=R<=n) 第二行n个数表示这个数列。(ai<=109)
输出描述:
输出一行表示答案,由于答案可能很大,请输出答案模109+7的值。
示例1
输入
5 1 5 1 2 3 4 5
输出
16
示例2
输入
4 1 4 4 4 4 4
输出
0
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100005
const ll Mod = 1e9+7;
ll a[N];
ll n,L,R;
ll Num[2][2];///第一个数组代表位置的奇偶性,第二个数代表第n位贡献 0 还是 1
ll Solve(ll l,ll r)
{
ll res = 0;
for(ll j=0; j<31; j++)
{
ll num = 0;
memset(Num,0,sizeof(Num));
for(ll i=1; i<=n; i++)
{
if(i>=l)Num[i&1][(a[i-l]>>j)&1]++;///更新的是我们要的区间值(从【i-l】-【i】)
num = (num + (Num[i&1][!(a[i]>>j&1)]))%Mod;
if(i>=r)Num[i&1][(a[i-r]>>j)&1]--;
}
res = (res + num*((1LL<<j)%Mod))%Mod;
}
return res;
}
int main()
{
while(~scanf("%lld%lld%lld",&n,&L,&R))
{
if(L&1)L++;
if(R&1)R--;
memset(a,0,sizeof(a));
if(L>R){
printf("0\n");
return 0;
}
for(ll i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
}
for(ll i=1;i<=n;i++)
a[i]=a[i-1]^a[i];
printf("%lld\n",(Solve(L,R)+Mod)%Mod);
}
}