(二进制 异或)Team Formation --ZOJ --3870

链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3870

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#problem/I   (密码:0817)

题目大意:从n个数中取2个数,问有多少种方法取的两个数的异或大于两个数的最大数
思路:如果x的最高位i位是1,y的位是0,且y比x大,i不是y的最高位,异或后这一位变成1,且yi位以前的1也可以保存,则异或后肯定比两个数的最大值还大

先把数组用快排从大到小排一下序, 再把每个数转分别换为二进制,在二进制中是 0 的就在相应的位置加 1, 另外如果首位是 1 的话,就把 sum(最后求的值) 加上相应位置上的值

举个例子:

1 2 3 4 5 

快排后是: 5 4 3 2 1 

对应的二进制是: 

 0  0  0  0

     1  0  1  b[1]++;

     1  0  0  b[1]++,  b[0]++;

         1  1  sum += b[1];

         1  0  b[0]++,  sum += b[1];

             1  sum += b[0];

比赛的时候,我没看这题,一直是队友们在做,我也不知道是什么意思,学长在结束给我们讲的时候,刚开始没懂什么意思,因为我不知道题意,没敢乱插话, 但是听他们说了一会儿,懂题意了,学长也很认真的讲了,知道了这题的思路,现在实现一下,是关于二进制的东西,接触的不多,觉得都很神奇,另外自己懂的太少了,还有一定要把深搜好好练练!!!

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;

#define N 100005

int cmp(int a, int b)
{
    return a>b;
}

int main()
{
    int t;
    scanf("%d", &t);

    while(t--)
    {
        int n, i, b[65]={0}, x[N]={0}, sum=0;

        scanf("%d", &n);

        for(i=1; i<=n; i++)
            scanf("%d", &x[i]);

        sort(x+1, x+n+1, cmp);

        for(i=1; i<=n; i++)
        {
            int j=0, a[64]={0};
            while(x[i])
            {
                a[++j] = x[i]%2;
                x[i] /= 2;
            }
            if(a[j]) sum += b[j];

            while(j)
            {
                if(!a[j])
                    b[j]++;
                j--;
            }
        }

        printf("%d
", sum);
    }
    return 0;
}
勿忘初心
原文地址:https://www.cnblogs.com/YY56/p/4737787.html