题解:P12177 [蓝桥杯 2025 省 Python B] 异或和
guoshengyu1231 · · 题解
前言
由于这题原本是给python代码写的,所以我们用c++写暴力枚举也可以过,但这题标准答案是用
思路
既然要让时间复杂度降低至
实现
大致的框架已经有了,接着我们需要考虑如何将我们的思路用代码实现出来。既然外层循环只是用来枚举位的,那我们可以不用管。重要的是在内层循环中如何统计每个数在这个位中做出的贡献。这个我们得先回看公式:
可以看到,如果先不考虑后面的
那么现在问题来了,现在还得乘上
现在还有一个问题等待着我们解决,那就是每一位上
示例
输入:
3
1 2 3
转化成二进制就是这样子的:
0 1
1 0
1 1
先来看第一位。此时枚举到第一个数由于此时
再来看第二位。第一个数依然贡献为
最后累加总贡献,得数为
代码
#include<bits/stdc++.h>
#define int __int128
using namespace std;
const int maxn=100005;
int n,a[maxn],ans;
int read()
{
int num=0;
char s[100];scanf("%s",s);
for(int i=0;i<strlen(s);i++) num=num*10+s[i]-'0';
return num;
}
void write(int num)
{
if(num>9) write(num/10);
putchar(num%10+'0');
}
signed main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int k=0;k<=20;k++)
{
int cnt[2]={0,0};
int sum[2]={0,0};
for(int i=1;i<=n;i++)
{
int bit=(a[i]>>k)&1;
ans+=sum[bit^1]*(1<<k);
cnt[bit]++;
sum[0]+=cnt[0];sum[1]+=cnt[1];
}
}
write(ans);
return 0;
}
代码解释
- 读写处理:由于答案较大,需要用
__int128来存储。但__int128不能直接输入和输出,所以需要转换为字符串来处理。 - 逐位处理:对于每一位
k (0 到20 ),统计该位上1 和0 的个数(cnt_1 ,cnt_0 )以及它们的权值(sum_1 ,sum_0 )。 - 贡献计算:
- 如果
a_i 的第k 位为1 ,则与之前所有第k 位为0 的数组成数对,贡献为sum_0\times 2ᵏ 。 - 如果
a_i 的第k 位为0 ,则与之前所有第k 位为1 的数组成数对,贡献为sum_1\times 2ᵏ 。
- 如果
- 更新权值:代码中的
bit 代表a_i 的第k 位。并且让cnt_{bit} 加1 ,表示该位上bit 的个数加1 。然后就是让每一位上0 和1 的权值加上相对应的个数。\\