(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题意:传送门
原题目描述再最下面。
给你n(1e5)个数,每个数范围1e4。问有多少对数的异或和位k。
思路:
考虑暴力枚举,但是不是直接枚举n。而是离散化之后枚举n,统计异或和二进制中1的数量。记得预先记录下每个数出现的次数。
对于统计二进制位中1的个数有很多方法。
AC代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <bitset>
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long LL;
const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
int n, k;
int ar[N], br[N], now[N];
LL num[N];
void init(){
memset(num,0,sizeof(num));}
int main(int argc, char const *argv[]){
while(~scanf("%d%d", &n, &k)){
init();
for(int i = 0; i < n; ++i){
scanf("%d", &ar[i]);
br[i] = ar[i];
num[ar[i]]++;
}
sort(br, br+n);
int p = 0;
for(int i = 1; i < n; ++i){
if(br[i]!=br[i-1]){
br[++p] = br[i];
}
}
for(int i = 0; i < n; ++i){
now[i] = lower_bound(br, br+p+1, ar[i]) - br;
}
LL ans = 0;
for(int i = 0; i <= p; ++i){
for(int j = i; j <= p; ++j){
bitset<32> a(br[i]^br[j]);
if(a.count()==k){
if(i==j){
ans += num[br[i]]*(num[br[j]]-1)/2;
}else{
ans += num[br[i]]*num[br[j]];
}
}
}
}
printf("%lld\n", ans);
}
return 0;
}
统计二进制中1的数量:
//方法一:
int bitCount(unsigned int n){
unsigned int tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111);
return ((tmp + (tmp >> 3)) & 030707070707) % 63;
}
//方法二:
bitset<32> a(n);
a.count();
//方法三:
__builtin_popcount(n)//返回二进制位中有多少个1
__builtin_parity(n)//返回二进制位中1的数量的奇偶性,奇数返回1,偶数返回0
__builtin_ffs(n)//返回二进制末尾最后一个1的位置,从一开始
__builtin_ctz(n)//返回二进制末尾后面0的个数,当n为0时,和n的类型有关