传送门
题意:给一个序列,让改变序列的顺序,使其经过一个运算,最后值最大。
分析:本题考就考这个运算,这个运算就是二进制,所以考的就是二进制。分析这个运算:(以下摘自tql tql tql tql)
/-------------------------------------------------------------------------------------------/
我们看这样一个操作他代表着什么?
我们把x,y拆解成二进制,x|y就相当于让两方都有1的一起有1了,然后−y就是让y位置上有1的减去。
举个例子,比如说x=1101,y=0111,那么就相当于说把x的最后一位1和第二位1带走了。
把所有数字拆成二进制,如果一个位置上的1,出现了多次(大于1),那么这个位置上的1肯定留不住。
所以我们就找最高位的出现一次的1,然后把它放到最前面去,之后的数字随便摆放。
可以模拟一下这个样例,9 5 9,把5摆到最前面上是最优解。
/---------------------------------------------------------------------------------------------/
也就是说,这个运算f(a,b)的结果是:将a,b转化为二进制,a为1,b为0的位是1,其他位是0。
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define sx(x) scanf("%d",&x)
using namespace std;
int a[100000+100];
int num[50];
int main()
{
int n;
sx(n);
memset(num,0,sizeof(num));
int cnt=-1;
for(int i=1;i<=n;i++)
{
sx(a[i]);
int x=a[i];
int tmp=0;
while(x) //将x转化成二进制,统计每个数每位1的数目
{
if(x&1)
num[tmp++]+=1;
else
num[tmp++]+=0;
x>>=1;
}
cnt=max(cnt,tmp); //最大位数
}
int pos=-1; //右移pos位
for(int i=cnt-1;i>=0;i--)
{
if(num[i]==1)
{
pos=i;
break;
}
}
if(pos==-1){
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
cout<<endl;
return 0;
}
for(int i=1;i<=n;i++){
if(a[i]>>pos&1){
swap(a[i],a[1]);
break;
}
}
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
cout<<endl;
return 0;
}
补充,把一个数的二进制的各个位都求出来:
while(x) //将x转化成二进制,统计每个数每位1的数目
{
if(x&1) //and 最后一位与1进行and
num[tmp++]=1;
else
num[tmp++]=0;
x>>=1; //右移
}