Zoj 3870——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
解题思路:第二组样例化为二进制分别为 1 10 11 100 101。可以发现,如果要让一个数增大,只要该数化为二进制后的出现0的位置跟1异或就会变大,同时需要满足另一个数的最高位为该数出现0位置的位数,如10可以跟1异或变为11 ,100可以跟10、11、1异或分别变为110,111,101,而101只能跟两位的进行异或,因为它的0出现的位置为第二位,最后求和就行了。
#include<bits/stdc++.h> using namespace std; int a[101000]; void solve(int n) { int num[50],num_1[50]; //num_1[i]表示某数化为二进制最高位为i的个数 //num[i]记录某数化为二进制后最高位为i且与前边出现数字异或值满足条件的组合的个数 sort(a,a+n);//将所给数组由小到大排序 memset(num,0,sizeof(num)); memset(num_1,0,sizeof(num_1)); int tm=a[0]; int pos_1=0,pos_0=0; //pos_0记录化为二进制过程中0出现的位置 //pos_1记录化为二进制过程中1出现的位置 while(tm!=0){ //处理数组a中最小的值 if(tm%2==0){ pos_0=pos_1+1; /* 由于这是a数组的第一个数且num1、num数组初始值都为0,所以这里没有求 这个数化二进制过程中出现0的位置在前边的数化二进制过程中为最高位的位 置的个数 */ } tm>>=1; pos_1++; } num_1[pos_1]++; //最高位为pos_1位置的数组变量自加 for(int i=1;i<n;i++) { pos_1=0,pos_0=0; tm=a[i]; int tmp=0; while(tm!=0){ if(tm%2==0){ pos_0=pos_1+1; tmp+=num_1[pos_0]; //tmp累加前边二进制最高位为pos_0位置的个数 } tm>>=1; pos_1++; } num_1[pos_1]++; num[pos_1]+=tmp; //这个数可以跟前边的数异或值增大的个数 } int ans=0; for(int i=0;i<50;i++) { ans+=num[i]; } printf("%d\n",ans); } int main(){ int t; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); solve(n); } return 0; } /* 5 5 1 2 3 4 5 */