题目
给定 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=0∑2k≤sn2k×((i=1∑nj=0∑i−1((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时,能产生影响的情况:
- 第 k k k位不是1且前 k − 1 k-1 k−1位 ≤ s [ k ] \leq s[k] ≤s[k]的前 k − 1 k-1 k−1位
- 第 k k k位是1且前 k − 1 k-1 k−1位 > s [ k ] >s[k] >s[k]的前 k − 1 k-1 k−1位
当 s [ i ] s[i] s[i]的第 k k k位为0时,能产生影响的情况:
- 第 k k k位不是1且前 k − 1 k-1 k−1位 > s [ k ] >s[k] >s[k]的前 k − 1 k-1 k−1位
- 第 k k k位是1且前 k − 1 k-1 k−1位 ≤ s [ k ] \leq s[k] ≤s[k]的前 k − 1 k-1 k−1位
那么这可以用树状数组记录
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);
}