两区间异或和最大
Posted nonames
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两区间异或和最大相关的知识,希望对你有一定的参考价值。
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; }
以上是关于两区间异或和最大的主要内容,如果未能解决你的问题,请参考以下文章
CF703D Mishka and Interesting sum