nowcoder 小AA的数列

这道题是二进制的改进题目,目的是利用二进制来减少时间复杂度

这类题对数学要求比较高!!!

首先要明确几个定理

1.异或运算(^)是满足交换律和结合律

2.a^b^a=b

3.   a^b=c  <=>  a=c^b  


首先!先看看这个问题是如何与二进制扯上关系的!!

目的:求一个区间的异或和

可以先把区间的数都看成二进制数(实质上^运算就是按照二进制算的)

假如:对于二进制的第 i 位数字 如果区间中(即运算过程中)的1的个数为奇数,那么最后也为1

            那么,如果是偶数,那么最后也为0  比如  7^5^6  =  4

             1           1           1                1    (3个1,1的个数为奇数)

             1           0           1      =        0    (2个1,1的个数为偶数)

             1           1           0                0     (2个1,1的个数为偶数)

那么对于这个区间如果想计算最后的异或和,那么其实就可以用每一位二进制最后的结果(0或者1)

乘以这一位的权重


那么问题来了!这好像没啥卵用啊

这道题要算长度为l的区间(l为偶数),要查询很多的区间

这样写也肯定要超时啊!!!

别急!先做个预处理,开一个数组num,用来储存前n项异或和

然后别忘了定理  2

如果用  num[ j ]^num[ i ]  ( j > i )   结果会是什么

没错,算出了从i到j的异或和

然后还有

要求区间【l,r】第i位的异或值

即num【r】^num【l】   

因为只有异或结果为1才有贡献,即  num【r】^num【l】=1

即表示如果满足上式,该位有贡献值

那么 我们只要找一下有多少个区间有贡献值,记为ans,然后用ans乘以二进制的权重

这样就求出来二进制位的值

那么有多少个区间??

如果l为奇数,那么r必定为偶数

如果l为偶数,那么r必定为奇数

那么只要找一下l前面的奇数偶数的个数,那么不就知道了有多少个区间了???(注意要在题目给定的长度里)


#include<bits/stdc++.h>  
#define N 100005  
#define P pair<int,int>  
using namespace std;  
typedef long long ll;  
const int M=1e9+7;  
int a[N],dp[2][2];  
int main()  
{  
    int n,l,r;  
    scanf("%d%d%d",&n,&l,&r);  
    for(int i=1;i<=n;i++){  
        scanf("%d",&a[i]);  
        a[i]^=a[i-1];  
    }  
    if(l&1)l++;  
    if(r&1)r--;  
    if(l>r){  
        printf("0\n");  
        return 0;  
    }  
    ll ans=0;  
    for(int i=0;i<32;i++){  
        ll tmp=0;  
        memset(dp,0,sizeof(dp));  
        for(int j=1;j<=n;j++){  
            if(j>=l)dp[(j-l)&1][((a[j-l]>>i)&1)^1]++;  
            tmp=(tmp+dp[j&1][(a[j]>>i)&1])%M;  
            if(j>=r)dp[(j-r)&1][((a[j-r]>>i)&1)^1]--;  
        }  
        ans=(ans+tmp*(1LL<<i)%M)%M;  
    }  
    printf("%lld\n",(ans+M)%M);  
    return 0;  
}  

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值