zoj3870-Team Formation(异或运算+数学规律)

题意:

给出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);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值