《TZOJ4986Team Formation》

这题挺好的吧:一开始看成或了。是异或。

首先,我们排个升序。

显然对于一个数,要将他变大,肯定是要和他小的来异或。

那么由于0异或上一个数没有变化。

所以我们不考虑0的情况。

首先,如果小的数的最高位的1和大的数的这一位都是1。

那么这个大的数显然会变小,且就算后面的都满足0 1都不会大。

因为2^i > 2^(i-1) + 2^(i-2) + ... 2^0

所以,我们只需要去记录bit[i],表示以i位是1且是最高位的1的个数。

然后从大到小去遍历大的数,统计每个位的情况即可。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<string,int> pii;
const int N = 1e5+5;
const int M = 2e5+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

int a[N];
int bit[35];
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        memset(bit,0,sizeof(bit));
        int n;n = read();
        for(rg int i = 1;i <= n;++i) a[i] = read();
        sort(a+1,a+n+1);
        LL ans = 0;
        for(rg int i = 1;i <= n;++i)
        {
            int f = 1;
            for(rg int j = 35;j >= 0;--j)
            {
                if((1LL<<j) > a[i]) continue;
                int k = (a[i]>>j)&1;
                if(k == 0) ans += bit[j];
                else if(f) bit[j]++,f = 0;
            }
        }
        printf("%lld\n",ans);
    }
    system("pause");    
}
View Code

 

posted @ 2020-09-10 21:23  levill  阅读(117)  评论(0编辑  收藏  举报