牛客提高D1t2 最小生成链

分析

我们发现可以把题目转化为:有一个序列a,问它的排列中相邻两个值异或的最大值的最小值

我们发现序列的构成一定是前几位全是一样的

从某一位开始左面全是0右面全是1

所以只要找到一种方案是的交界两个值异或最小即可

把是0的插入01trie,每次拿是1的查询异或最小值

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int n,m,sum[60000100][2],trie[60000100][2],cnt;
long long a[1000100],res,ans;
inline void q(long long x){
    int i,p=0;
    for(i=59;i>=0;i--){
      int wh=(x&(1ll<<i))?1:0;
      if(trie[p][wh]){
        p=trie[p][wh];
      }else p=trie[p][wh^1],res|=(1ll<<i);
    }
    return;
}
inline void ins(long long x){
    int i,p=0;
    for(i=59;i>=0;i--){
      int wh=(x&(1ll<<i))?1:0;
      if(!trie[p][wh])
        trie[p][wh]=++cnt;
      p=trie[p][wh];
    }
    return;
}
signed main(){
    int i,j,k,pl=-1;
    scanf("%d",&n);
    ans=(1ll<<60);
    for(i=1;i<=n;i++){
      scanf("%lld",&a[i]);
      for(j=0;j<60;j++){
          int wh=((1ll<<j)&a[i])?1:0;
        sum[j][wh]++;
      }
    }
    for(i=59;i>=0;i--){
      if(sum[i][0]==n||sum[i][1]==n)continue;
      pl=i;
      break;
    }
    for(i=1;i<=n;i++)
      if(!((1ll<<pl)&a[i])){
          ins(a[i]);
      }
    for(i=1;i<=n;i++)
      if((1ll<<pl)&a[i]){
          res=0;
        q(a[i]);
        //cout<<i<<' '<<res<<endl;
        ans=min(ans,res);
      }
    if(pl==-1)puts("0");
      else printf("%lld\n",ans);
    return 0;
}
posted @ 2019-08-24 19:05  水题收割者  阅读(285)  评论(0编辑  收藏  举报