zoj 3870 Team Formation (数位统计问题)

题意:

给出n个数组成的序列,求满足这样的数对的个数,i!=j,a[i]^a[j]>max(a[i],a[j]);

题解:

这题可以从二进制的角度去观察,我们可以枚举数对中的某个数i,然后计算有多少个j满足。对于j个数的计算,通过2进制数位的分析会发现,只要小于a[i]并且最高为和a[i]的对应位是不同的数就满足条件。预处理出最高位数是1的个数,剩下就是暴力枚举i和a[i]的位。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define B(x) (1<<(x))
using namespace std;
typedef long long ll;
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
void cmax(ll& a,ll b){ if(b>a)a=b; }
void cmin(ll& a,ll b){ if(b<a)a=b; }
void add(int& a,int b,int mod){ a=(a+b)%mod; }
void add(ll& a,ll b,ll mod){ a=(a+b)%mod; }
const int oo=0x3f3f3f3f;
const ll OO=0x3f3f3f3f3f3f3f3f;
const ll MOD=1000000007;
const int maxn = 100000 ;
int num[40],a[maxn],bit[40];

int get_bit(int n){
    int dig=0;
    while(n){
        n/=2;
        dig++;
    }
    return dig;
}

void Count(int n){
    int bit=get_bit(n);
    num[bit]++;
}

int get_bin(int n){
    int len=0;
    while(n){
        bit[++len]=n%2;
        n/=2;
    }
    return len;
}

int main(){
    //freopen("E:\\read.txt","r",stdin);
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(num,0,sizeof num);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            Count(a[i]);
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            int len=get_bin(a[i]);
            for(int j=len;j>=1;j--)
                if(!(bit[j]&1))ans+=num[j];
        }
        cout<<ans<<endl;
    }
    return 0;
}


你可能感兴趣的:(zoj 3870 Team Formation (数位统计问题))