题目
给定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=0∑2k≤sn2k×((i=1∑nj=0∑i−1((s[i]−s[j])>>k)mod2)mod2)
恭喜得到了一个比O(n2)O(n^2)O(n2)还要慢的算法,所以
kkk和iii想要优化可能很困难,那么考虑优化jjj
当s[i]s[i]s[i]的第kkk位为1时,能产生影响的情况:
- 第kkk位不是1且前k−1k-1k−1位≤s[k]\leq s[k]≤s[k]的前k−1k-1k−1位
- 第kkk位是1且前k−1k-1k−1位>s[k]>s[k]>s[k]的前k−1k-1k−1位
当s[i]s[i]s[i]的第kkk位为0时,能产生影响的情况:
- 第kkk位不是1且前k−1k-1k−1位>s[k]>s[k]>s[k]的前k−1k-1k−1位
- 第kkk位是1且前k−1k-1k−1位≤s[k]\leq s[k]≤s[k]的前k−1k-1k−1位
那么这可以用树状数组记录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);
}
本文探讨了给定一系列数值时,如何高效计算所有可能区间内连续数值和的异或值。通过深入分析,提出了一种利用树状数组优化计算过程的方法,将时间复杂度从O(n^2)降低到O(nlog^2s[n])。文章详细解释了算法原理,并提供了实现代码。
407

被折叠的 条评论
为什么被折叠?



