链接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3870
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#problem/I (密码:0817)
题目大意:从n个数中取2个数,问有多少种方法取的两个数的异或大于两个数的最大数
思路:如果x的最高位i位是1,y的位是0,且y比x大,i不是y的最高位,异或后这一位变成1,且yi位以前的1也可以保存,则异或后肯定比两个数的最大值还大
先把数组用快排从大到小排一下序, 再把每个数转分别换为二进制,在二进制中是 0 的就在相应的位置加 1, 另外如果首位是 1 的话,就把 sum(最后求的值) 加上相应位置上的值
举个例子:
5
1 2 3 4 5
快排后是: 5 4 3 2 1
对应的二进制是:
0 0 0 0
1 0 1 b[1]++;
1 0 0 b[1]++, b[0]++;
1 1 sum += b[1];
1 0 b[0]++, sum += b[1];
1 sum += b[0];
比赛的时候,我没看这题,一直是队友们在做,我也不知道是什么意思,学长在结束给我们讲的时候,刚开始没懂什么意思,因为我不知道题意,没敢乱插话, 但是听他们说了一会儿,懂题意了,学长也很认真的讲了,知道了这题的思路,现在实现一下,是关于二进制的东西,接触的不多,觉得都很神奇,另外自己懂的太少了,还有一定要把深搜好好练练!!!
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cstdlib> using namespace std; #define N 100005 int cmp(int a, int b) { return a>b; } int main() { int t; scanf("%d", &t); while(t--) { int n, i, b[65]={0}, x[N]={0}, sum=0; scanf("%d", &n); for(i=1; i<=n; i++) scanf("%d", &x[i]); sort(x+1, x+n+1, cmp); for(i=1; i<=n; i++) { int j=0, a[64]={0}; while(x[i]) { a[++j] = x[i]%2; x[i] /= 2; } if(a[j]) sum += b[j]; while(j) { if(!a[j]) b[j]++; j--; } } printf("%d\n", sum); } return 0; }
勿忘初心