题意:
给出n个数,求出所有两个数异或值大于其中任何一个数的所有组合。
分析:
暴力肯定超时,(冥思苦想了许久,最后看了别人的题解才恍然大悟。)对于一个数n,如果将二进制表示形式下最左端出现0的位置变为1,那么变化之后的数肯定比原数大。
思路:
首先求出每个数二进制表示形式下最左端1出现的位置,再枚举每个数二进制表示形式下最左端0的位置,从左往右,累加上所有0与配对的情况。
下面是代码
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+10;
int a[maxn],bit[32];
///方法一
void found(int num){///找出每个数二进制形式下的最左端1的位置(实际上用的是最左端1的后一位)
int l = 31;
while(l>=0){
if(num&(1<<l)) {
bit[l]++;
return ;
}
l--;
}
}
///方法二
/*
void record(int num){
int pos=0;
while(num){
pos++;
num/=2;
}
if(pos)
bit[pos-1]++;
}
*/
int main(){
int t,n,i;
long long sum;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i = 0; i < n; i++)
scanf("%d",&a[i]);
sum = 0;
memset(bit,0,sizeof(bit));
for(i = 0; i < n; i++)
record(a[i]);
//found(a[i]);
for(i = 0; i < n; i++){
int l = 31;
while(l>=0){
if(a[i]&(1<<l)) break;
l--;
}
while(l>=0){
if(!(a[i]&(1<<l))) sum += bit[l];
l--;
}
}
printf("%lld\n",sum);
}
}