• [BZOJ4260] Codechef REBXOR


    传送门:>Here<

    题意:给出一个长度为N的序列,求$Max{ (a[l_1]⊕...⊕a[r_1]) + (a[l_2]⊕...⊕a[r_2]) }$ ($1 leq l_1 leq r_1 < l_2 leq r_2 leq N$)  ($N leq 4*10^5$)

    解题思路

      首先理解题目的意思——求解两段区间,使这两段区间的异或和的和最大。

      我们可以考虑维护两个数组$L$和$R$,其中$L[i]$表示在区间$[1, i]$中选出一段区间的最大异或和。$R[i]$则表示区间$[i, N]$。因此答案一定是$Max{ L[i] + R[i+1] }$。因此现在只需要考虑如何求出这两个数组就行了

      因为$L$和$R$的求法是类似的,所以我们就只谈$L$的求法。

      考虑维护一个异或前缀和数组$x$,$x[i]$表示$a[1] ⊕ a[2] ⊕ ... ⊕ a[i-1] ⊕ a[i]$。

      我们有以下几条性质:

        异或是满足交换律的                      (1)

        相同的数异或为0                           (2)

        0异或一个数字得到那个数字本身  (3)

      因此我们就可以得到前缀和数组$x[i] ⊕ x[j]$就表示区间$[j, i]$的异或和。因为$x[i]  ⊕  x[j] = a[1] ⊕ ... ⊕ a[i] ⊕ a[1] ⊕ ... ⊕ a[j]$,把相同的放在一起抵消了,剩下的就是区间$[j, i]$的异或和

      因此要得到区间$[1, i]$的最大异或子段和,就等同于求与$x[i]$异或和最大的$x[j]$了,这篇文章中我们已经详细阐述了这个问题的求法。因此问题就解决了

      考虑$L[i]$怎么转移?$L[i] = Max{ L[i-1], x[i], x[i] ⊕ x[j] }$。其中$L[i-1]$表示当前数$a[i]$不参与到区间内(我就是忘记考虑这种情况了,两个区间不一定只相距1啊!!1),$x[i]$表示整个区间都参与,不需要再找最大的$x[j]$了。

    Code

      做L和R时要分开,数组要清零

    /*By DennyQi*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 400010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w;
    }
    int N;
    int a[MAXN],x[MAXN],L[MAXN],R[MAXN];
    int ch[MAXN<<5][2],End[MAXN<<5],num_node;
    bool b[40];
    inline void Convert(int x){
        memset(b,0,sizeof(b));
        for(int i = 33; x > 0; --i){
            b[i] = x%2;
            x >>= 1;
        }
    }
    inline void Insert(int x){
        Convert(x);
        int u=0;
        for(int i = 1; i <= 33; ++i){
            if(!ch[u][b[i]]) ch[u][b[i]] = ++num_node;
            u = ch[u][b[i]];
        }
        End[u] = x;
    }
    inline int Query(int x){
        int u=0;
        Convert(x);
        for(int i = 1; i <= 33; ++i){
            if(!ch[u][!b[i]]) u = ch[u][b[i]];
            else u = ch[u][!b[i]];
        }
        return End[u];
    }
    inline void Clear(){
        memset(End,0,sizeof(End));
        memset(ch,0,sizeof(ch));
        num_node = 0;
    }
    int main(){
        N=r;
        for(int i = 1; i <= N; ++i){
            a[i]=r;
            x[i] = x[i-1] ^ a[i];
        }
        L[1] = x[1];
        Insert(x[1]);
        for(int i = 2; i <= N; ++i){
            L[i] = Max(x[i], Max(L[i-1], Query(x[i]) ^ x[i]));
            Insert(x[i]);
        }
        Clear();
        for(int i = N; i >= 1; --i) x[i] = x[i+1] ^ a[i];
        R[N] = x[N];
        Insert(x[N]);
        for(int i = N-1; i >= 1; --i){
            R[i] = Max(x[i], Max(R[i+1], Query(x[i]) ^ x[i]));
            Insert(x[i]);
        }
        int ans = -1;
        for(int i = 1; i < N; ++i) ans = Max(ans, L[i]+R[i+1]);
        printf("%d", ans);
        return 0;
    }
  • 相关阅读:
    各种数据库默认端口总结
    Entity Framework学习
    Entity Framework学习
    .Net MVC API初试
    MongoDB Shell
    MongoDB安装及简单实验
    Android Studio记录
    Android使用Fragment程序崩溃
    git操作笔记
    centos防火墙设置
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9426109.html
Copyright © 2020-2023  润新知