NEUOJ711 异星工厂 字典树+贪心

题意:你可以收集两个不相交区间的权值,区间权值是区间异或,问这两个权值和最大是多少

分析:很多有关异或求最大的题都是利用01字典树进行贪心,做这个题的时候我都忘了。。。最后是看别人代码的时候才想起来这个套路

          l[i],记录,从 1 到 i  里 最大的异或区间权值,

          r[i], 记录,从  i 到 n 里 最大的异或区间权值

       这样两轮插入,然后查询贪心就行了,插入的是前缀和后缀的异或2进制序列,从大的开始(贪心)

注:吐槽,其实都是套路,异或和求最大,往往要利用字典树进行贪心

#include <cstdio>
#include <iostream>
#include <ctime>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=3e6+5;
const int M=1e5+5;
const int INF=0x3f3f3f3f;
struct Node{
  int nex[2];
}p[N+M];
int cnt;
int newnode(){
   ++cnt;
   p[cnt].nex[0]=p[cnt].nex[1]=-1;
   return cnt;
}
int x[M],a[M];
void insert(int pos){
  int now=0;
  for(int i=30;i>=0;--i){
    int cur=(x[pos]&(1<<i))>0?1:0;
    if(p[now].nex[cur]==-1)
      p[now].nex[cur]=newnode();
    now=p[now].nex[cur];
  }
}
int getmax(int pos){
  int now=0,ret=0;
  for(int i=30;i>=0;--i){
    int cur=(x[pos]&(1<<i))>0?1:0;
    if(p[now].nex[cur^1]!=-1){
      ret+=(1<<i);
      now=p[now].nex[cur^1];
    }
    else now=p[now].nex[cur];
   
  } 
  return ret;
 
}
int l[M],r[M];
int main()
{
    int n;
    while(~scanf("%d",&n)){
      cnt=-1;newnode();
      insert(0);
      for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        x[i]=(x[i-1]^a[i]);
        l[i]=max(getmax(i),l[i-1]);
        insert(i);
      }
      r[n+1]=x[n+1]=0;
      cnt=-1;newnode();
      insert(n+1);
      for(int i=n;i;--i){
        x[i]=(x[i+1]^a[i]);
        r[i]=max(getmax(i),r[i+1]);
        insert(i);
      }
      LL ret=0;
      for(int i=1;i<n;++i)
        ret=max(ret,1ll*l[i]+1ll*r[i+1]);
      printf("%lld\n",ret);
    }
    return 0;
}
View Code

 

posted @ 2016-06-15 17:29  shuguangzw  阅读(355)  评论(0编辑  收藏  举报