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

本文探讨了给定一系列数值时,如何高效计算所有可能区间内连续数值和的异或值。通过深入分析,提出了一种利用树状数组优化计算过程的方法,将时间复杂度从O(n^2)降低到O(nlog^2s[n])。文章详细解释了算法原理,并提供了实现代码。

题目

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


分析

一定要把异或拆开,可以得到答案是
∑k=02k≤sn2k×((∑i=1n∑j=0i−1((s[i]−s[j])>>k) mod 2) mod 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(n2)O(n^2)O(n2)还要慢的算法,所以
kkkiii想要优化可能很困难,那么考虑优化jjj
s[i]s[i]s[i]的第kkk位为1时,能产生影响的情况:

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

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

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

那么这可以用树状数组记录sss中二进制位上0或1的个数,从而把时间优化到O(nlog2s[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);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值