题目内容
给定一个长度为 n n n 的数组 a a a 。
定义
f
(
x
,
y
)
=
(
x
∣
y
)
−
y
f(x,y)=(x|y)-y
f(x,y)=(x∣y)−y ,其中
∣
|
∣ 是按位或运算。
定义数组
a
a
a 的权值为
f
(
f
(
.
.
.
f
(
a
1
,
a
2
)
,
.
.
.
,
a
n
−
1
)
,
a
n
)
f(f(...f(a_1,a_2),...,a_{n-1}),a_n)
f(f(...f(a1,a2),...,an−1),an)
现在重新对数组 a a a 排序,使得其权值最大,输出任意一种排序后权值最大的数组 a a a 。
数据范围
- 1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1≤n≤105
- 0 ≤ a i ≤ 1 0 9 0\leq a_i\leq 10^9 0≤ai≤109
题解
对于数的每个二进制位考虑,可以发现,如果第 i i i 个二进制位出现次数超过 1 1 1 次,那么这个二进制位在运算后必然为 0 。
因此我们只需要选择二进制位只出现一次,且最大的二进制位放在开头即可。
时间复杂度: O ( 30 n ) O(30n) O(30n)
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
vector<int> idx(30, -1);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 30; ++j) {
if (a[i] >> j & 1) {
if (idx[j] == -1) idx[j] = i;
else idx[j] = -2;
}
}
}
int t = -1;
for (int j = 29; j >= 0; --j) {
if (idx[j] >= 0) {
t = idx[j];
break;
}
}
if (t != -1) {
swap(a[0], a[t]);
}
for (int i = 0; i < n; ++i) cout << a[i] << " \n"[i + 1 == n];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}