1. 程式人生 > >Team Formation (思維)

Team Formation (思維)

Team Formation

 ZOJ - 3870 

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{AB}).

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 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
題意: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\n",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\n",ans);
47     }
48 }

orz 都是什麼神仙隊友啊~~