Codeforces Round #618 (Div. 2) C.Anu Has a Function

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),an1),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;
}
原文地址:https://www.cnblogs.com/wyh447154317/p/12289656.html