题目地址
思路:
根据题目给出的条件,
f
(
f
(
…
f
(
f
(
a
1
,
a
2
)
,
a
3
)
,
…
a
n
−
1
)
,
a
n
)
f(f(\dots f(f(a_1, a_2), a_3), \dots a_{n-1}), a_n)
f(f(…f(f(a1,a2),a3),…an−1),an)
e
p
:
f
(
11
,
6
)
=
(
11
∣
6
)
−
6
=
15
−
6
=
9
ep:f(11, 6) = (11|6) - 6 = 15 - 6 = 9
ep:f(11,6)=(11∣6)−6=15−6=9
我们可以分析两个数的运算,可知:
11
:
1011
11 :1011
11:1011
6
:
0110
6 : 0110
6:0110
11
∣
6
−
6
=
1001
11 |6 - 6=1001
11∣6−6=1001
即:11的二进制中的1与6的二进制的1相同位置的数都被消去了。即11被消去了一位进制。那么我们可以推出,我们要找一个数
a
k
ak
ak,再从
a
k
ak
ak中扣去除
a
k
ak
ak以外的所有数.
可得公式:
f ( x , y ) = f ( x ∣ y ) − y < = > f ( x & ∼ y ) f\left( x,y\right) =f\left( x|y\right) -y<=>f\left( x\& \sim y\right) f(x,y)=f(x∣y)−y<=>f(x&∼y)
即可得到
(
a
k
&
(
∼
a
n
)
&
(
∼
a
n
+
1
)
&
.
.
.
.
.
.
.
.
)
\left( ak\& (\sim an\right)\& (\sim an +1)\&........)
(ak&(∼an)&(∼an+1)&........)
我们使
a
k
ak
ak所拥有的进制是唯一且最大的,那么最后留下的数一定是最大的。
步骤
按照分析,先分离每个数的进制,统计每一位出现的次数,如果出现了一次,那么我们保留,并维护一个最大数及下标。剩余的数任意顺序排列即可,因为最终一定会消去 。
AC代码
import java.math.BigInteger;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int num[] = new int[100005];
int cnt[] = new int[105];
int n = cin.nextInt();
for(int i = 0;i < n;i++)num[i] = cin.nextInt();
for(int i = 0;i < n;i++) {
for(int c = 0; c <= 30;c++) {
if(((num[i] >> c) & 1) == 1) ++cnt[c];///统计每一位出现的次数。
}
}
int idx = 0;
int sum = 0;
int ans = 0;
for(int i = 0;i < n;i++) {
for(int c = 0; c <= 30;c++) {
if(((num[i] >> c) & 1) == 1 && cnt[c] == 1) {
sum += (1 << c);
}
}
if(sum > ans) {
ans = sum;
idx = i;
}
sum = 0;
}
System.out.print(num[idx] + " ");
for(int i = 0;i < n;i++) {
if(i == idx)continue;
System.out.print(num[i] + " ");
}
System.out.println();
}
}