Codeforces Round #672 (Div. 2) B. Rock and Lever

Danik urgently needs rock and lever! Obviously, the easiest way to get these things is to ask Hermit Lizard for them.

Hermit Lizard agreed to give Danik the lever. But to get a stone, Danik needs to solve the following task.

You are given a positive integer n, and an array a of positive integers. The task is to calculate the number of such pairs (i,j) that i<j and ai & aj≥ai⊕aj, where & denotes the bitwise AND operation, and ⊕ denotes the bitwise XOR operation.

Danik has solved this task. But can you solve it?

Input
Each test contains multiple test cases.

The first line contains one positive integer t (1≤t≤10) denoting the number of test cases. Description of the test cases follows.

The first line of each test case contains one positive integer n (1≤n≤105) — length of the array.

The second line contains n positive integers ai (1≤ai≤109) — elements of the array.

It is guaranteed that the sum of n over all test cases does not exceed 105.

Output
For every test case print one non-negative integer — the answer to the problem.

Example
inputCopy
5
5
1 4 3 7 10
3
1 1 1
4
6 2 5 3
2
2 4
1
1
outputCopy
1
3
2
0
0
Note
In the first test case there is only one pair: (4,7): for it 4 & 7=4, and 4⊕7=3.

In the second test case all pairs are good.

In the third test case there are two pairs: (6,5) and (2,3).

In the fourth test case there are no good pairs.

题意:
给出长度 n 1e5的序列 ,问满足 i < j && ai & aj >= ai ^ aj 的对数 有多少

思路:
1e5 类似逆序对的问题。 位运算一般要按位来考虑
由&的性质得 两个数相与只会 小于等于 原来的数 1 & 1 = 1 1 & 0 = 0 0 & 0 = 0
由异或的性质可得 1 ^ 1 = 0 , 1 ^ 0 = 1 0 ^ 0 = 0
所以说我们只看最高位 最高位无非就两种情况 要么相等 要么不相等
相等的话 &运算 >= 异或运算 (等于是因为都为0的情况) 反之则 异或运算 > &运算

回到题目 需要满足题给条件的话 只有最高位均为1的情况 才能满足
用标记数组 记录之前该位最高位为1的情况 相加即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 50;

#define LL long long

LL f[55];

void db(){//二进制打表
    f[0] = 1;
    for(int i = 1;;i ++){
        f[i] = f[i - 1] << 1;
        if(f[i] > 1e9){
            break;
        }
    } 
}

int main(){
    db();

    int t;
    cin >> t;

    while(t --){
        int n;
        cin >> n;

        vector <int> a(n);

        for(int i = 0;i < n;i ++){
            cin >> a[i];
        }

        LL res = 0;
        LL vis[55] = {0};
        
        for(int i = 0;i < n;i ++){
            int top = 0;
            while(f[top] <= a[i])++ top;//找到大于当前数值
            res += vis[top - 1];//-1 则为当前的最高位  加上之前出现过的
            vis[top - 1] ++;//加上这一次出现的
        }
        
        cout << res << '\n';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值