题目链接
题意大概就是给你一个公式:f(x,y)=(x|y)−y,其中 | 是按为或运算,再给你一个数组an,问怎样排列才能让f(f(…f(f(a1,a2),a3),…an−1),an)得到的结果最大。
拿第一组数据来看
将其转换成二进制:
4: 100
0: 000
11:1011
6: 110
这样,f(11,6) :
(1011)|(110)-110
(1011)|(110)=1111
1111-110=1001;
f(11,4):
(1011)|(100)-100
(1011)|(100)=1111
1111-100=1011;
由此不难发现,f(x,y)就是先找出y二进制为1的位,再将x中的这些位全部变成0。
所以不难得出思路就是将具有 最高且不重复二进制位的数放在第一个,其它数任意(若无符合条件的,即所有数相同,则任意排列)。
例如 10011 10100 1000,虽然第一二两个都具有最高二进制位,但其重复了,所以应将1000放在第一个。
代码如下
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int we[40],biao[40];//1e9最高是2^30,我们开到40。
void f(int i)//统计每个二进制位出现的个数
{
int t=a[i],k=0;
while(t)
{
if(t%2!=0)
{
we[k]++;//统计个数
biao[k++]=i;//记录位置
t/=2;
}
else
{
t/=2;
k++;
}
}
return;
}
int main()
{
int t,n,bb=-1;//bb初始化为-1作用看后面
cin>>n;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
f(i);//统计二进制位
}
for(int i=39;i>=0;i--)//查找每个二进制位
{
if(we[i]==1)//出现我们要找的东西
{
bb=biao[i];//记录位置
break;
}
}
int flag=0;//用于输出前置空格
if(bb!=-1)//判断是否所有数都相同(即是否出现了所需要的数)
{
printf("%d",a[bb]);//出现了即输出
flag=1;//格式
}
for(int i=0;i<n;i++)
{
if(i==bb)
continue;
if(flag)
printf(" ");
printf("%d",a[i]);
flag=1;
}
printf("\n");
return 0;
}