题目大意:所给的一个数组中任意两个数异或值大于这个两个数,即i^j > max(i, j),问有多少个这样的异或
1^1 = 0, 0^0 = 0, 1^0 = 1, 0^1 = 1
如果x的最高位i位是1,y的位是0,且y比x大,i不是y的最高位,异或后这一位变成1,且yi位以前的1也可以保存,则异或后肯定比两个数的最大值还大
先把数组用快排从大到小排一下序, 再把每个数转分别换为二进制,在二进制中是 0 的就在相应的位置加 1, 另外如果首位是 1 的话,就把 ans(最后求的值) 加上相应位置上的值
举个例子:
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 ans+= b[1];
1 0 b[0]++, ans+= b[1];
1 ans+= b[0];
#include<stdio.h> #include<stdlib.h> #include<string.h> #define N 100010 int ans, a[N], b[110], c[110];//注意b,c的数组不能开太大,否则TLE(开始为图省事直接用N,直接TLE) int cmp(const void *a, const void *b) { return *(int *)b - *(int *)a; } void slove(int n) { int i, j = 0; memset(c, 0, sizeof(c)); while(n) { c[j++] = n % 2; n /= 2; }//将n转化成二进制 if(c[j - 1])//如果最高位是1与0异或其值必然大于这两个数,所以ans直接加上相应位置的值 ans += b[j - 1]; for(i = 0 ; i < j ; i++) if(!c[i]) b[i]++;//c中等待1异或的0元素个加1 } int main() { int n, t, i; scanf("%d", &t); while(t--) { ans = 0; memset(b, 0, sizeof(b)); scanf("%d", &n); for(i = 0 ; i < n ; i++) scanf("%d", &a[i]); qsort(a, n, sizeof(a[0]), cmp); for(i = 0 ; i < n ; i++) slove(a[i]); printf("%d\n", ans); } return 0; }