XOR Clique(按位异或)
XOR Clique(按位异或):
传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4057
准备:异或:参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0^0=0, 0^1=1, 1^0=1, 1^1=0;
即:参加运算的两个对象,如果两个相应位为“异”,则该位结果为1,否则为0;
题意:
有一个a1到an的序列,问能不能找到一个长度为S的序列,对于在S里面的任意的i,j满足ai⊕aj<min(ai,aj) 这个条件,两个数的异或小于这两个数的最小值,要求输出S的最大长度。
解题思路:
多找几组数据就会发现若想异或结果小于最小值,只需要两个数二进制形式位数相同, 即二进制前面第一位都为1,进行异或运算后就会第一位变为0,自然比原来两个数都小 所以只需要将序列中所有数的二进制形式位数进行统计即可(学长说二进制运算一般找最高位是常用的方法)
以下为AC代码:
1 /* */ 2 # include <bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 6 const int INF = 0x3f3f3f3f; 7 const int MAXN = 40;///用来记录路最高位的值,2的30次方就可以达到1e9 8 int a[MAXN];///用来记录某一最高位所包含的数有几个 9 10 11 int bt(int x) 12 { 13 int cnt = 0; 14 while( x ) 15 { 16 x >>= 1;///x除以2,10进制化2进制运算 17 cnt++; 18 } 19 return cnt;///返回最高位 20 } 21 22 int main() 23 { 24 int T 25 cin >> T; 26 while( T-- ) 27 { 28 memset(a, 0, sizeof(a)); 29 int n; 30 scanf("%d", &n); 31 int ans = 0; 32 for( int i=0; i<n; i++ ) 33 { 34 int e; 35 scanf("%d", &e); 36 ans = max(ans, ++a[bt(e)]);///找出最高位为bt(e)的值的个数,找出哪一最高位对应的数最多,极为最长子集包含的数的个数 37 } 38 printf("%d\n", ans); 39 } 40 return 0; 41 }
以下为超时代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int t; 6 scanf("%d", &t); 7 while (t--) 8 { 9 int n; 10 int a[100005]={0};///相当于建了一个桶来标记 11 scanf("%d", &n); 12 int k=0; 13 for (int i = 0; i < n; ++i) 14 { 15 int x,sum=0; 16 scanf("%d", &x); 17 while(x) 18 { 19 sum++; 20 x/=2; 21 } 22 a[sum]++; 23 } 24 for(int i=0;i<10000;i++)///这样遍历,无用循环做的次数太多了,所以超时 25 { 26 k=max(k,a[i]); 27 } 28 printf("%d\n",k ); 29 } 30 return 0; 31 }