zoukankan      html  css  js  c++  java
  • BZOJ 4260 Codechef REBXOR (区间异或和最值) (01字典树+DP)

    <题目链接>

    题目大意:
    给定一个序列,现在求出两段不相交的区间异或和的最大值。

    解题分析:

    区间异或问题首先想到01字典树。利用前缀、后缀建树,并且利用异或的性质,相同的两个数异或变成0,从而将前缀操作转化为区间操作,比如:$(a_1 oplus a_2)oplus(a_1 oplus a_2 oplus a_3 oplus a_4) = a_3 oplus a_4$。然后利用简单的$dp$,$predp[i]$记录前$[1~i]$ 任意区间的区间异或最大值(注意不是前缀),$nxtdp$同理记录后缀区间的最大值。

    本题空间卡得比较紧,所以没有另外用一个$val[now]$数组记录Trie树前缀节点所表示的值,而是在$query$中用$ans$代替。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 4e5+5;
    typedef long long ll;
    ll n,pos=1,arr[N],nxt[N*30][2],predp[N],nxtdp[N];
    
    template<typename T>
    inline T read(T&x) {     
        x = 0;int f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch == '-') f=-1; ch=getchar(); }
        while(ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
        return x*f;
    }
    void Insert(ll x){
        int now=1;
        for(int i=30;i>=0;i--){
            int to=(x>>i)&1;
            if(!nxt[now][to])nxt[now][to]=++pos;
            now=nxt[now][to];
        }
    }
    ll query(ll x){
        int now=1;ll ans=0;
        for(int i=30;i>=0;i--){
            int to=(x>>i)&1;
            if(nxt[now][to^1])now=nxt[now][to^1],ans+=(1<<i);   //因为最终异或得到的答案就是x中所不包含的数位
            else now=nxt[now][to];
        }
        return ans;
        //return x^val[now];      因为本题空间卡得紧,所以就不能写成这种形式
    }
    int main(){
        read(n);
        for(int i=1;i<=n;i++)read(arr[i]);
        for(int cur=0,i=1;i<=n;i++){
            Insert(cur^=arr[i]);
            predp[i]=max(query(cur),predp[i-1]);  //因为一个数被异或两次等于0,所以这里利用Trie树的前缀操作来实现区间操作
        }//得到 i 的前缀区间异或和的最大值
        memset(nxt,0,sizeof(nxt));
        for(int cur=0,i=n;i>=1;i--){
            Insert(cur^=arr[i]);
            nxtdp[i]=max(query(cur),nxtdp[i+1]);
        }//得到 i 的后缀异或区间和的最大值
        ll ans=-1;
        for(int i=1;i<=n;i++)ans=max(ans,predp[i]+nxtdp[i]);
        printf("%lld
    ",ans);
    }

    2019-03-02

  • 相关阅读:
    next()nextLine()以及nextInt()的区别及用法【转载】
    JAVA集合 list set map
    JAVA求回文数
    左移右移操作_进制转换与区分
    window_mysql踩坑
    centos_mysql踩坑
    【纪中受难记】——C3D6:大小不分
    zzLinux 中直接 I/O 机制的介绍https://www.ibm.com/developerworks/cn/linux/l-cn-directio/
    zz-zookeeper 启动失败 BindException: Address already in use 或者Error contacting service. It is probably not running
    zz---对象存储(Object-based Storage)概述
  • 原文地址:https://www.cnblogs.com/00isok/p/10462732.html
Copyright © 2011-2022 走看看