链接:小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; 
}