两区间异或和最大

https://blog.csdn.net/zuzhiang/article/details/79877109

题意:给xi你 n 个数,让你求两个不相交的区间元素异或后的和的最大值。本题中 n 的上限是  4*10^5.

解法:求出前缀异或和和后缀异或和,dp【i】表示前i个数任意区间的最大异或和。

根据性质异或和性质dp【i】异或dp【j】相同部分会抵消,可以根据递推求出dp【i】

转化为dp【i-1】+ suf【i】最大值,可以防止区间重叠。

#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include <vector>
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
using namespace std;
typedef unsigned long long ll ;
const int N = 400009;
int tree[N*32][2] , vis[N*32] , tol;
int a[N];
int pre[N] , suf[N];
int dp[N] ;

void insert(int x)
{
    int u = 0 ;
    for(int i = 31 ; i >= 0 ; i--)
    {
        int p = (x >> i) & 1 ;
        if(!tree[u][p]) tree[u][p] = ++tol ;
        u = tree[u][p];
    }
    vis[u] = x ;
}

int research(int x)
{
    int u = 0 ;
    for(int i = 31 ; i >= 0 ; i--)
    {
        int p = (x >> i) & 1 ;
        if(tree[u][p^1]) u = tree[u][p^1];
        else u = tree[u][p];
    }
    return x ^ vis[u];
}

int main()
{
    int n ;
    scanf("%d" , &n);
    for(int i = 1 ; i <= n ; i++)
    {
        scanf("%d" , &a[i]);
    }
    for(int i = 1 ; i <= n ; i++) pre[i] = pre[i-1] ^ a[i];//前缀异或和
    for(int i = n ; i >= 1 ; i--) suf[i] = suf[i+1] ^ a[i];
    insert(pre[0]);
    for(int i = 1 ; i <= n ; i++)
    {
        dp[i] = max(dp[i-1] , research(pre[i]));//求前i个数中任意区间异或最大
        insert(pre[i]);
    }
    tol = 0 ;
    memset(vis , 0 , sizeof(vis));
    memset(tree , 0 , sizeof(tree));
    int ans = -INF;
    insert(suf[n+1]);
    for(int i = n ; i >= 1 ; i--)
    {
        ans = max(ans , research(suf[i]) + dp[i-1]);//后缀异或和+前缀异或和最大
        insert(suf[i]);
    }
    cout << ans << endl ;

    return 0;
}
posted @ 2020-01-21 18:31  无名菜鸟1  阅读(712)  评论(0编辑  收藏  举报