f(x,y)可以看做把 y二进制位中为1的位 对应的 x中相应位 变为0。因此第一个数以后的数顺序不影响结果。只需寻找拥有 最高独占1位 的数,将其放于第一位即可。
f(x,y)=(x|y)−y按二进制拆位发现对于第i位
若x、y第i位均为1,函数结果第i位为0
若x第i位为0,y第i位为1,函数结果第i位为0
若x第i位为1,y第i位为0,函数结果第i位为1
而对于f(f(…f(f(a1,a2),a3),…an−1),an)无论顺序怎么排 只要第i位为1的个数≥2 n次函数运算后结果第i位为0
证明:
1.若a1第i位为0 那么无论怎么排 n次函数运算后结果第i位为0
2.若a1第i位为1 遇到第二个第i位为1的数后 函数结果第i位为0 之后就变成了第一种情况
故最后答案只取决于第一个数,为第一个数中在n个数中只出现过一次的位
所以为了答案最大,从高位开始贪心,只要该位只出现过一次就退出循环 因为后面位的影响之和显然没有该位大
反思:1.对于涉及位运算且求最大值的题,一般都是从高位到低位贪心,应该果断拆位的
不应该仅按数的顺序来,还要根据二进制位
2.把函数等价为了x-x&y 迭代的时候犯了煞笔错误f(f(x,y),z)=x-x&y-x&y&z了 事实上无论怎么迭代函数结果都只有两项
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int a[N]; int main(){ int n; cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; int ans=0; for(int i=30;i>=0;i--){ int cnt=0,pos=0; for(int j=1;j<=n;j++) if(a[j]&(1<<i)){ cnt++; pos=j; } if(cnt==1){ ans=pos; break;} } if(ans==0)for(int i=1;i<=n;i++)cout<<a[i]<<' '; else { cout<<a[ans]<<' '; for(int i=1;i<=n;i++) if(ans!=i)cout<<a[i]<<' '; } return 0; }