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 Tindicating 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 ithinteger 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
题意:T组样例,每组N个数,问从中最多选几组,每组两个数,这两个数的异或值大于这两个数的较大的数。
有些模糊的知识点:
lower_bound()函数:
功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置.
注意:如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!
函数upper_bound()
功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
注意:返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置。同样,如果val大于数组中全部元素,返回的是last。(注意:数组下标越界)
题解:%我的两位大神队友 tql orz
对于一个数,如果想让它和另一个比它小的数异或后值反而比它大,那么我们只需要让该数的最高非零位之前的第一个零位变成1即可。例如10011 我们只需要让从左到右第一个0位变成1 即1000-1111中任何一个数和10011异或都可以变得比10011大
为了方便,我们先对数组进行从小到大排序,然后确定了该数的最高0位,即确定了可以异或的范围,然后通过lower_bound()函数和upper_bound()函数,确定该数组中可以取到的数。
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int maxn=1e5+10;
7 typedef long long ll;
8 int casen;
9 ll a[maxn];
10 ll sum[maxn];
11 ll digit[50];
12 int main()
13 {
14 ll n;
15 scanf("%d",&casen);
16 while(casen--)
17 {
18 memset(digit,0,sizeof(digit));
19 scanf("%lld",&n);
20 ll ans=0;
21 for(ll i=0;i<n;i++)
22 {
23 scanf("%lld",&a[i]);
24 }
25 // cout<<"####"<<endl;
26 sort(a,a+n);
27 for(ll i=0;i<n;i++)
28 {
29 ll sum=0;
30 ll tmp=a[i];
31 while(tmp)
32 {
33 if(tmp%2==0)
34 {
35 ll low=1<<sum;
36 ll high=(1<<(sum+1))-1;
37 ll ul=lower_bound(a,a+n,low)-a;
38 ll ur=upper_bound(a,a+n,high)-a;
39 ans+=ur-ul;
40 }
41 tmp>>=1;
42 sum++;
43 }
44 }
45 printf("%lld
",ans);
46 }
47 }
方法2:先对数组进行从小到大排序,然后统计每一个数的所有非零位,放在digit数组中,然后遍历数组,加上每个数最高零位对应的出现过的1 的数量。
例如第二个样例 1 2 3 4 5分别为
01 digit[0]=1
10 digit[1]=1 digit[0]=1 ans+=digit[0]=1;
11 digit[1]=2 digit[0]=2
100 digit[0]=2 digit[1]=2 digit[2]=1 ans+=digit[1]=3
101 digit[0]=3 digit[1]=2 digit[2]=2 ans+=digit[1]=6
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int maxn=1e5+10;
7 typedef long long ll;
8 int casen;
9 ll a[maxn];
10 ll sum[maxn];
11 ll digit[50];
12 int main()
13 {
14 ll n;
15 scanf("%d",&casen);
16 while(casen--)
17 {
18 memset(digit,0,sizeof(digit));
19 scanf("%lld",&n);
20 ll ans=0;
21 for(ll i=0;i<n;i++)
22 {
23 scanf("%lld",&a[i]);
24 }
25 // cout<<"####"<<endl;
26 sort(a,a+n);
27 for(ll i=0;i<n;i++)
28 {
29 ll tmp=a[i];
30 // cout<<tmp<<endl;
31 ll sum=0;
32 while(tmp)
33 {
34 // cout<<"tmp="<<tmp<<endl;
35 if(tmp%2==0)
36 {
37 ans+=digit[sum];
38
39 }
40 tmp>>=1;
41 sum++;
42 }
43 digit[sum-1]++;
44 }
45 /**/
46 printf("%lld
",ans);
47 }
48 }
orz 都是什么神仙队友啊~~