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;
}
原文:https://www.cnblogs.com/nonames/p/12222746.html