#树状数组#BZOJ 4888 洛谷 3760 异或和

题目

给定 n n n个数,求它们所有区间的连续和的异或值


分析

一定要把异或拆开,可以得到答案是
∑ k = 0 2 k ≤ s n 2 k × ( ( ∑ i = 1 n ∑ j = 0 i − 1 ( ( s [ i ] − s [ j ] ) > > k )   m o d   2 )   m o d   2 ) \sum_{k=0}^{2^k\leq s_n}2^k\times ((\sum_{i=1}^n\sum_{j=0}^{i-1}((s[i]-s[j])>>k)\bmod 2)\bmod 2) k=02ksn2k×((i=1nj=0i1((s[i]s[j])>>k)mod2)mod2)
恭喜得到了一个比 O ( n 2 ) O(n^2) O(n2)还要慢的算法,所以
k k k i i i想要优化可能很困难,那么考虑优化 j j j
s [ i ] s[i] s[i]的第 k k k位为1时,能产生影响的情况:

  1. k k k位不是1且前 k − 1 k-1 k1 ≤ s [ k ] \leq s[k] s[k]的前 k − 1 k-1 k1
  2. k k k位是1且前 k − 1 k-1 k1 > s [ k ] >s[k] >s[k]的前 k − 1 k-1 k1

s [ i ] s[i] s[i]的第 k k k位为0时,能产生影响的情况:

  1. k k k位不是1且前 k − 1 k-1 k1 > s [ k ] >s[k] >s[k]的前 k − 1 k-1 k1
  2. k k k位是1且前 k − 1 k-1 k1 ≤ s [ k ] \leq s[k] s[k]的前 k − 1 k-1 k1

那么这可以用树状数组记录 s s s中二进制位上0或1的个数,从而把时间优化到 O ( n l o g 2 s [ n ] ) O(nlog^2s[n]) O(nlog2s[n])
但是要注意树状数组记录的可能是0,所以要整体右移一位,而且貌似不用long long,而且树状数组要注意清空


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans; 
}
int n,s[100001],lim,ans;
struct szsz{
    int c[1000101];
    inline void add(int x,int y){for (++x;x<=lim+1;x+=-x&x) c[x]+=y;}
    inline signed answ(int x){rr int ans=0; for (++x;x;x-=-x&x) ans+=c[x]; return ans;}
    inline signed aasw(int l,int r){return answ(r)-answ(l);}
}c0,c1;
signed main(){
    n=iut();
    for (rr int i=1;i<=n;++i) s[i]=s[i-1]+iut();
    for (rr int k=0;(1<<k)<=s[n];++k){
        lim=(1<<k)-1; rr int sum=0;
        for (rr int i=0;i<=n;++i){
            rr int now=s[i]&lim;
            if ((s[i]>>k)&1) sum+=c0.aasw(-1,now)+c1.aasw(now,lim),c1.add(now,1);
                else sum+=c1.aasw(-1,now)+c0.aasw(now,lim),c0.add(now,1);
        }
        ans+=(1<<k)*(sum&1),memset(c0.c,0,sizeof(c0.c)),memset(c1.c,0,sizeof(c1.c));
    }
    return !printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值