链接:小AA的数列
题意:求长度在 区间内的偶数长度区间异或和之和。
题解:显然区间异或和的和可以按为拆开分开计算,最后在累加上去(因为每一位异或时互不干扰)。现在考虑怎么把范围限制在 中。可以发现,我们容易求出大于某个数的长度的答案,所以答案就是
(数位
计算区间答案的思想)。递推时注意
是可由
的答案继承过来的,但是在算答案累加时是得按最短长度去继承的。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int mod=1e9+7;
ll f[maxn][2],s[maxn],a[maxn],n,L,R;
inline void update(int j)
{
int p=s[j]^s[j-2];
if(p)
{
f[j][0]=f[j-2][1];
f[j][1]=f[j-2][0]+1;
}
else
{
f[j][0]=f[j-2][0]+1;
f[j][1]=f[j-2][1];
}
}
inline ll DP(int len)
{
ll ans=0;
for(int i=0;i<=31;i++)
{
ll tmp=0; f[0][0]=f[0][1]=f[1][0]=f[1][1]=0;
for(int j=1;j<len;j++)
{
s[j]=s[j-1]^((1ll<<i)&a[j]);
}
for(int j=2;j<len;j++)update(j);
for(int j=len;j<=n;j++)
{
s[j]=s[j-1]^((1ll<<i)&a[j]);
int p=s[j]^s[j-len];
if(p)tmp+=f[j-len][0]+1;
else tmp+=f[j-len][1];
update(j);
}
ans=(ans+(1ll<<i)*tmp%mod)%mod;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>n>>L>>R;
int l1=(L+1>>1)<<1,l2=(R>>1)+1<<1;
for(int i=1;i<=n;i++)cin>>a[i];
cout<<((DP(l1)-DP(l2))%mod+mod)%mod<<endl;
return 0;
} 
京公网安备 11010502036488号