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

来源:互联网 发布:单片机报警电路设计 编辑:程序博客网 时间:2024/05/16 15:01

题意:

给出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);    }}
原创粉丝点击