4260: Codechef REBXOR
时间限制: 10 Sec 内存限制:256 MB提交: 535 解决: 243
[ 提交 ][ ][ ]
题目描述
输入
输入数据的第一行包含一个整数N,表示数组中的元素个数。
第二行包含N个整数A1,A2,…,AN。
输出
输出一行包含给定表达式可能的最大值。
样例输入
5
1 2 3 1 2
1 2 3 1 2
样例输出
6
提示
满足条件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。
对于100%的数据,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。
题意:找出两个不相交区间异或和的最大和值。
题解:
看到区间异或,首先这题应该是用01字典树去写。我们求一个前缀异或和,求一个后缀异或和。维护一个dp数组,dp[i]表示以i为结尾的最大区间异或值。再通过后缀数组维护max。具体解释在代码中。
看到区间异或,首先这题应该是用01字典树去写。我们求一个前缀异或和,求一个后缀异或和。维护一个dp数组,dp[i]表示以i为结尾的最大区间异或值。再通过后缀数组维护max。具体解释在代码中。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define mem(a) memset(a, 0, sizeof(a))
#define eps 1e-5
#define MAX 400030
#define INF 0x3f3f3f3f
using namespace std;
int pre[MAX];
int suf[MAX];
int a[MAX];
int dp[MAX];
int ch[32*MAX][2];
int val[32*MAX];
int sz;
void init()
{
sz=1;
mem(ch[0]);
}
void Insert(int a)
{
int u=0;
for(int i=31;i>=0;i--)
{
int c=((a>>i)&1);
if(!ch[u][c])
{
mem(ch[sz]);
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=a;
}
int query(int a)
{
int u=0;
for(int i=31;i>=0;i--)
{
int c=((a>>i)&1);
if(ch[u][c^1])
u=ch[u][c^1];
else
u=ch[u][c];
}
return val[u]^a;
}//以上为模板
int main()
{
int n;
scanf("%d",&n);
init();
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
pre[0]=suf[n+1]=0;
for(int i=1;i<=n;i++)
pre[i]=pre[i-1]^a[i];
for(int i=n;i>0;i--)
suf[i]=suf[i+1]^a[i];
mem(dp);
Insert(0);
for(int i=1;i<=n;i++)
{
dp[i]=max(dp[i-1],query(pre[i]));
Insert(pre[i]);//这里刚开始难理解,为什么加进去的是前缀和,得到的却是连续区间异或和。因为你加入的前缀和,会跟之前加进去的前缀和进行异或操作求得最大值,而跟前面的进行异或操作,就使得一个数跟自己异或。
}
init();
int maxn=0;
Insert(0);
for(int i=n;i>0;i--)
{
maxn=max(maxn,query(suf[i])+dp[i-1]);
Insert(suf[i]);
}
printf("%d\n",maxn);
}