题目链接
题意给你n个数,之后定义一个函数f(x, y) = (x | y) - y,让你求f(f(…f(f(a1,a2),a3),…an−1),an)最大的a_1-a_n的顺序
思路:其实我们可以发现f(x, y) = (x|y) - y可以等价于x - (x & y)即减去x和y二进制相同位的位置,那么我们可以很快的发现如果a_1-a_n
结论:如果一个二进制位出现了大于1次,得到的最大值二进制1在这一位是一定不存在的,那么我们可以直接求出来最后的最大值,接下来就是调出a_1-a_n的顺序
解法:我们只需要不断把二进制1只出现一次且当前最大值最大的数放在前面就好了。
#include<bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
#define pii pair<int,int>
#define x first
#define y second
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn],n,bit[100];
int main(){
IOS;
cin >> n;
for(int i = 1; i <= n; i++)cin >> a[i];
if(n == 1){
cout << a[1] << endl;
return 0;
}
// x - x & y
ll mx = 0;
for(int i = 1; i <= n; i++){
for(int j = 31; j >= 0; j--){
if(a[i] >> j & 1)bit[j]++;
//求出a_i的所有二进制1
}
}
for(int i = 1; i <= n; i++){
ll now = 0;
for(int j = 0; j <= 31; j++){
//如果当前a_i二进制1存在 且当前所有数的二进制1只有一个
//那么答案 += 1ll << j 如果二进制1出现两次
//那么当前这个二进制一定会减少 所以不需要更新
if((a[i] >> j & 1) && bit[j] == 1)now += (1ll << j);
}
if(now >= mx)mx = now, swap(a[i], a[1]);
}
for(int i = 1; i <= n; i++){
if(i == 1)cout << a[i];
else cout << ' ' << a[i];
}
}