【每日一题】5月25日 小AA的数列

小AA的数列

https://ac.nowcoder.com/acm/problem/14414

题目大意:
小AA找到了一个数列,她想要知道这个数列中所有长度为偶数的区间异或和之和 。
后来她发现这个问题太简单了,于是她加了一个限制,要求区间长度在[L,R]之间,
图片说明

参考wxyww的优美代码.

https://blog.nowcoder.net/n/b1816a1594eb41389e78659f45467d06

分析:异或和题目经典套路按二进制位进行计算。
对每一个数进行二进制拆分,然后每一位依次做前缀和。图片说明 表示前i个长度为偶数的前缀区间异或值为j的个数是多少。
并且由于区间长度必须是偶数,那么做前缀和的时候图片说明 应该由图片说明 进行转移累加.
一个非常优美的实现就是前缀和从下标图片说明 开始进行。
那么对于当前第图片说明 位置。
如果前缀异或和为1, 以当前为右区间的有贡献的合法偶数长度区间的方案数是
图片说明 .
如果前缀异或和为0, 以当前为右区间的有贡献的合法偶数长度区间的方案数是
图片说明 .
最后方案数乘以二进制下第i位数为1 的十进制大小。所有位数贡献累加起来就是答案。

#include<bits/stdc++.h>
using namespace std;

const int mod=1e9+7;
typedef long long ll;
const int maxn=1e5+10;
int sum[maxn][2],a[maxn],n,l,r;

ll solve( int x )
{
    sum[n][0]=1;
    for( int i=1;i<=n;i++ )
    {
        sum[i+n][0]=sum[i+n-2][0]+( ( a[i]>>x & 1 )^1 );
        sum[i+n][1]=sum[i+n-2][1]+( a[i]>>x & 1 );
    }
    ll res=0;
    for( int i=1;i<=n;i++ )
    {
        int R=i-l,L=i-r-2;
        if( a[i]>>x&1 ) res+=max(0,sum[R+n][0]-sum[L+n][0]);
        else res+=max(0,sum[R+n][1]-sum[L+n][1]);
    }
    return res%mod;
}


int main()
{
    cin>>n>>l>>r;
    if( l&1 ) l++;
    if( r&1 ) r--;
    for( int i=1;i<=n;i++ ) cin>>a[i];
    for( int i=1;i<=n;i++ ) a[i]^=a[i-1];
    ll ans=0;
    for( int i=0;i<30;i++ )    ans+=solve(i)*(1<<i)%mod;
    cout<<ans%mod<<endl;
    return 0;
} 
每日一题 文章被收录于专栏

每日一题

全部评论

相关推荐

totoroyyw:千年老妖😂
投递华为等公司10个岗位
点赞 评论 收藏
分享
赏个offer求你了:友塔HR还专门加我告诉我初筛不通过😂
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务