Team Formation 二进制的异或

For an upcoming programming contest, Edward, the headmaster of Marjar University, is forming a two-man team from N students of his university.

Edward knows the skill level of each student. He has found that if two students with skill level A and B form a team, the skill level of the team will be A ⊕ B, where ⊕ means bitwise exclusive or. A team will play well if and only if the skill level of the team is greater than the skill level of each team member (i.e. A ⊕ B > max{A, B}).

Edward wants to form a team that will play well in the contest. Please tell him the possible number of such teams. Two teams are considered different if there is at least one different team member.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer N (2 <= N <= 100000), which indicates the number of student. The next line contains N positive integers separated by spaces. The ith integer denotes the skill level of ith student. Every integer will not exceed 109.

Output

For each case, print the answer in one line.

Sample Input

2
3
1 2 3
5
1 2 3 4 5

Sample Output

1
6

因为最近我们省的省赛要开始了,所以我们老师让我们做了做浙江的省赛题,发现这道题目还是特别考思维的。

题目的意思是,在给定数字串中任选两个数,这两个数的异或值要大于他们两个中最大的一个(就是要大于他们两)

问你有多少种方案。

首先,这个题目暴力肯定是会超时的,我们队当时做的时候还有用01树的。其实根本不用这么麻烦,我们只要了解二进制的特性即可。

假设我们选了两个数,所有数的二进制最高位都是1,我们只需要保存最高位1的位置即可。

为什么呢:到时后,我们会把每个数最高位之后的0位全部找到,再在我们存储1位的数组里面寻找,假设找到了0-1对应,那么我们可以肯定的是这个1是较小数的最高位,且异或之后,大数的0变成了1,数值变大。

举个例子:5和3

二进制 : 101   11,

我们现在找到了5和3的最高位位置,数组a[3]=1,a[2]=1;  我们开始找0位,发现5的第二位是0,且a[2]=1(对应位是1),我们可以肯定,这个找到的”1“肯定是比5小的数二进制之后产生的“1”(原因就是我们存的1是最高位的1),那么0--1异或得1,大数(也就是5)的0位变成的1,数值变大。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

int a[100005];
int topp[35];
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		memset(topp, 0, sizeof(topp));
		int n;
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &a[i]);
			int now = a[i];
			int cnt = 0;
			while (now)//这个循环就是存最高位的1的位置
			{
				now >>= 1;
				cnt++;
			}
			topp[cnt]++;
		}
		int ans = 0;
		for (int i = 0; i < n; i++)
		{
			int now = a[i];
			int cnt = 0;
			while (now)
			{
				cnt++;
				if (now % 2 == 0)ans += topp[cnt];//找0位,找到之后把当前位是1的个数全部加起来
				now >>= 1;//继续向后找0位
			}
		}
		printf("%d\n", ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40620465/article/details/81975839