1. 程式人生 > 其它 >【Codeforces 1420 B】Rock and Lever,位運算,找規律

【Codeforces 1420 B】Rock and Lever,位運算,找規律

技術標籤:演算法

problem

B. Rock and Lever
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
“You must lift the dam. With a lever. I will give it to you.
You must block the canal. With a rock. I will not give the rock to you.”

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.

B.搖滾與槓桿
每次測試的時限1秒
每個測試的記憶體限制256 MB
輸入標準輸入
輸出標準輸出
“您必須提起水壩。用槓桿。我將它交給您。
您必須堵住運河。用一塊石頭。我不會把石頭給你。”

Danik迫切需要堅如磐石!顯然,獲得這些東西的最簡單方法是向隱士蜥蜴索取。

隱士蜥蜴同意給予丹尼克槓桿。但是,要想獲得成功,Danik需要解決以下任務。

給您一個正整數n和一個正整數陣列a。任務是計算i <j和ai&aj≥ai⊕aj的對(i,j)的數量,其中&表示按位與運算,⊕表示按位XOR運算。

Danik解決了此任務。但是你能解決嗎?

輸入項
每個測試包含多個測試用例。

第一行包含一個正整數t(1≤t≤10),表示測試用例的數量。測試用例的說明如下。

每個測試用例的第一行包含一個正整數n(1≤n≤105)-陣列的長度。

第二行包含n個正整數ai(1≤ai≤109)-陣列的元素。

保證所有測試用例的n之和不超過105。

輸出量
為每個測試用例列印一個非負整數—問題的答案。


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
注意
在第一個測試用例中,只有一對:(4,7):4&7 = 4,4⊕7= 3。

在第二個測試用例中,所有對都是好的。

在第三個測試用例中,有兩對:(6,5)和(2,3)。

在第四個測試用例中,沒有好的對。

Let’s take a pair (ai,aj) and see in which case ai & aj≥ai⊕aj will hold. For this we will follow the bits ai and aj from highest to lowest. If we meet two zero bits, the values of ai & aj and ai⊕aj will match in this bit, so we move on. If we meet a zero bit in ai and in aj —one bit(or vice versa), then we get ai & aj<ai⊕aj, and we can immediately say that the required condition is false. And if we meet two one bits, then the required condition is fulfilled, e. ai & aj>ai⊕aj, and then the bits can no longer be considered.

Now let’s consider the highest one bit in the number of ai (let it stand at pi position) and the highest single bit in the number of aj (let it stand at pj position). (Here, we consider that the bits are numbered in order of lowest to highest.) Then, pi=pj must hold. If pi>pj, then there is zero in the aj position and one unit in the ai position. But then from the reasoning above we get that ai & aj<ai⊕aj. The case of pi<pj is treated in a similar way.

It is also easy to see that if pi=pj then we automatically get the condition ai & aj>ai⊕aj.

From here the problem is solved. For each number we find the position of the highest one bit pi. Then we need to calculate the number of pairs of numbers, for which pi=pj. You may notice that the answer is ∑ℓkℓ⋅(kℓ−1)2, where kℓ — the number of numbers for which pi=pj.

The complexity of the solution is O(n).

讓我們取一對(ai,aj),看看在哪種情況下ai&aj≥ai⊕aj會成立。為此,我們將從最高到最低跟隨ai和aj位。如果我們遇到兩個零位,則ai&aj和ai⊕aj的值將在此位匹配,因此我們繼續。如果我們在ai和aj中都遇到一個零位-一位(或者反之亦然),那麼我們得到ai&aj <ai⊕aj,我們可以立即說出所需條件為假。如果我們滿足兩個一位,則滿足所需條件,例如e。 ai&aj>ai⊕aj,然後不再考慮這些位。

現在,讓我們考慮ai數的最高一位(讓它位於pi位置)和aj數的最高單一位(讓它站在pj位置)。 (在這裡,我們認為這些位是按從低到高的順序編號的。)然後,pi = pj必須成立。如果pi> pj,則aj位置為零,ai位置為1個單位。但是從上面的推理中我們得到了ai&aj <ai⊕aj。 pi <pj的情況以類似方式處理。

還很容易看到,如果pi = pj,則我們自動獲得條件ai&aj>ai⊕aj。

從這裡解決問題。對於每個數字,我們找到最高位pi的位置。然後我們需要計算數字對的數量,其中pi = pj。您可能會注意到答案是∑ℓkℓ⋅(kℓ−1)2,其中kℓ-pi = pj的數字數。

解決方案的複雜度為O(n)。

solution

/*
題意:
+ 給出一個長為n(<1e5)的陣列
+ 統計有幾對(i,j)滿足ai&aj>ai^aj
思路:
+ &是相同為1,^是相反為1。對於2個數(i,j),因為&和^都是逐位生成的,所以關鍵在於比較最高位。
+ 可以發現,當且僅當i的最高位1和j的最高位1位置相同時,滿足1&1>1^1,否則1&0<1^0或0&1<0^1.
+ 所以列舉第i位為1的數有幾個,相互之間構成對數+=n*(n-1)/2,複雜度為O(n)
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
int a[maxn];
int main(){
	int T;  cin>>T;
	while(T--){
		int n;  cin>>n;
		for(int i = 0; i < n; i++)
			cin>>a[i];
		LL ans = 0;
		for(int j = 30; j >= 0; j--){//int最多第31位,32位是符號位
			LL cnt = 0;
			for(int i = 0; i < n; i++){
				if(a[i]>=(1<<j) && a[i]<(1<<(j+1))){//如果第j位為1,累加
					cnt++;
				}
			}
			ans += cnt*(cnt-1)/2;
		}
		cout<<ans<<"\n";
	}
	return 0;
}