P9236 [蓝桥杯 2023 省 A] 异或和之和 题解
P9236 [蓝桥杯 2023 省 A] 异或和之和
首先,异或有一个重要的性质:
因为
有了这个式子,区间异或和就可以像前缀和一样处理了。
我们可以求出每一项的前缀异或和,记作
所以,我们用这个式子来求解每个区间的异或和,可以把每个子段的异或和的和转变为下面式子:(这里
但这个做法的复杂度是
在这个式子中,我们可以观察到,对于每一对
这个时候会发现推式子已经到达尽头了,再怎么推也不会得到新的结论。必须从其他方面考虑问题,比如异或运算的计算原理的方面。可以考虑把每个数按二进制拆分,在每一位上统计该位的贡献。由于最后是两两异或的求和,所以二进制拆分后打乱不会影响结果。
由于异或的运算法则是如果同位数字不同,那么运算结果的这一位为
对于每一个
由于这些数中必定两两异或,所以可以直接用乘法原理,求出该位最终为
时间复杂度
#include <bits/stdc++.h>
using namespace std;
long long n,a[100010],q[100010],w[100010][2],ans=0;
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)q[i]=q[i-1]^a[i];
for(int i=0;i<=n;i++)
for(int j=20;j>=0;j--)
w[j][(q[i]>>j)&1]++;
for(int i=0;i<=20;i++)
ans+=w[i][0]*w[i][1]*(1<<i);
printf("%lld",ans);
return 0;
}
AC记录