CodeForces Round # 618 div2 C题
Anu Has a Function
题干
Anu has created her own function f : f ( x , y ) = ( x ∣ y ) − y f : f(x,y)=(x|y)−y f:f(x,y)=(x∣y)−y where || | denotes the bitwise OR operation. For example, f ( 11 , 6 ) = ( 11 ∣ 6 ) − 6 = 15 − 6 = 9 f(11,6)=(11|6)−6=15−6=9 f(11,6)=(11∣6)−6=15−6=9 . It can be proved that for any nonnegative numbers x x x and y y y value of f ( x , y ) f(x, y) f(x,y) is also nonnegative.
She would like to research more about this function and has created multiple problems for herself. But she isn’t able to solve all of them and needs your help. Here is one of these problems.
A value of an array a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an is defined as 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)(see notes). You are given an array with not necessarily distinct elements. How should you reorder its elements so that the value of the array is maximal possible?
Input
The first line contains a single integer n ( 1 ≤ n ≤ 1 0 5 ) n (1 \le n \le 10^5 ) n(1≤n≤105).
The second line contains n n n integers a 1 , a 2 , … , a n ( 0 ≤ a i ≤ 1 0 9 ) a_1, a_2, \ldots, a_n ( 0 \le a_i \le 10^9 ) a1,a2,…,an(0≤ai≤109). Elements of the array are not guaranteed to be different.
Output
Output n n n integers, the reordering of the array with maximum value. If there are multiple answers, print any.
解题思路
直觉上,我们可以判断出在二进制层面 f ( x , y ) f(x,y) f(x,y)运算的过程中不会出现某一个二进制位被借位的情况(因为一般情况下的减法有可能出现这种情况)
//这里是按照传统的二进制减法来理解,当然计算机实现减法是用补码啦
我们采用一种类似于数学归纳法的方式证明这个结论
将 x , y x,y x,y的最低位记作 x 0 , y 0 x_0,y_0 x0,y0,若 x 0 ∣ y 0 = 0 x_0|y_0=0 x0∣y0=0则 x 0 = y 0 = 0 , f ( x 0 , y 0 ) = 0 x_0=y_0=0,f(x_0,y_0)=0 x0=y0=0,f(x0,y0)=0,若 x 0 ∣ y 0 = 1 且 x 0 = y 0 x_0|y_0=1\text{且}x_0=y_0 x0∣y0=1且x0=y0,则减法也不会发生借位
若 x 0 ∣ y 0 = 1 且 x 0 = 1 , y 0 = 0 x_0|y_0=1且x_0=1,y_0=0 x0∣y0=1且x0=1,y0=0显然不会借位,若 x 0 ∣ y 0 = 1 且 x 0 = 0 , y 0 = 1 x_0|y_0=1且x_0=0,y_0=1 x0∣y0=1且x0=0,y0=1也是没有发生借位。
我们发现针对最低位不会发生借位,不难归纳出对于每一位也是这样的。那么这个函数可以写为按位运算的形式
f ( x , y ) = x y ˉ f(x,y)=x\bar{y} f(x,y)=xyˉ其中 y ˉ \bar{y} yˉ表示对y按位取反
那么 f ( f ( … f ( f ( a 1 , a 2 ) , a 3 ) , … a n − 1 ) , a n ) = a 1 a 2 ˉ a 3 ˉ … a n ˉ = a 1 a n d ( a 2 o r a 3 o r … a n ) f(f(\dots f(f(a_1, a_2), a_3), \dots a_{n-1}), a_n)=a_1\bar{a_2}\bar{a_3}\dots \bar{a_n}=a_1~and~\text{~}(a_2~or~a_3~or\dots a_n) f(f(…f(f(a1,a2),a3),…an−1),an)=a1a2ˉa3ˉ…anˉ=a1 and (a2 or a3 or…an)
由或运算的分配律知整个式子的结果就是由 a 1 a_1 a1的选取决定的
那么我们怎么选取 a 1 a_1 a1呢?当然是暴力出奇迹啦!,每一个 a i a_i ai都计算一下就好了,这里要注意使用一下前缀和、后缀和的思想保存 [ a 1 , a i ] [a_1,a_i] [a1,ai]区间和 [ a j , a n ] [a_j,a_n] [aj,an]相或的结果。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
int a[maxn],qzh[maxn],hzh[maxn];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
qzh[i]=qzh[i-1]|a[i];
}
for(int i=n;i>=1;i--){
hzh[i]=hzh[i+1]|a[i];
}
int ans=-1,t,maxi=0;
for(int i=1;i<=n;i++){
t=a[i]&~(qzh[i-1]|hzh[i+1]);
if(t>ans){
ans=t;
maxi=i;
}
}
cout<<a[maxi]<<" ";
for(int i=1;i<=n;i++){
if(i!=maxi)cout<<a[i]<<" ";
}
}